Reputation: 103
While experimenting with Python and PyQt5 I got stuck on a problem. I have in my GUI few labels (QLabel) and images (QPixmap) and I want to draw something on them, depending on what the main program does. I can't figure out how though. For example, I change text on labels calling setLabels() from class BinColUI and I would like to draw something on them (i.e. QPainter.drawLine()) just after that. What I tried is not working, there's nothing drawn. My unsuccesful attempt is commented out in setLabels(). How do I do it?
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter, QPen
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QVBoxLayout, QWidget
class BinColUI(QMainWindow):
def __init__(self):
super().__init__()
self.initUi()
self.createLabelTop()
self.createLabelBot()
def initUi(self):
self.setWindowTitle('Bin Collection')
self.setFixedSize(500, 500)
# self.setStyleSheet('background-color: white')
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
def paintEvent(self, event):
self.qp = QPainter()
self.qp.begin(self)
self.drawLine(event, self.qp)
self.qp.end()
def drawLine(self, event, qp):
pen = QPen(Qt.red, 3, Qt.SolidLine)
qp.setPen(pen)
qp.drawLine(5, 5, 495, 5)
qp.drawLine(495, 5, 495, 495)
qp.drawLine(495, 495, 5, 495)
qp.drawLine(5, 495, 5, 5)
def createLabelTop(self):
self.label_top = QLabel('PLEASE WAIT')
self.label_top.setAlignment(Qt.AlignCenter)
self.label_top.setFixedSize(450, 60)
self.label_top.setStyleSheet("font: 14pt Bahnschrift; color: black; background-color: yellow")
self.generalLayout.addWidget(self.label_top, alignment=Qt.AlignCenter)
def createLabelBot(self):
self.label_bot = QLabel('PLEASE WAIT')
self.label_bot.setAlignment(Qt.AlignCenter)
self.label_bot.setFixedSize(450, 60)
self.label_bot.setStyleSheet("font: 14pt Bahnschrift; color: black; background-color: yellow")
self.generalLayout.addWidget(self.label_bot, alignment=Qt.AlignCenter)
def setLabels(self, texttop, textbot):
# qp = QPainter(self.label_top)
self.label_top.setText(texttop)
self.label_bot.setText(textbot)
# pen = QPen(Qt.red, 3)
# qp.setPen(pen)
# qp.drawLine(10, 10, 50, 50)
# self.label_top.repaint()
class BinColCtrl:
def __init__(self, view: BinColUI):
self._view = view
self.calculateResult()
def calculateResult(self):
line_top = 'NEW LABEL TOP'
line_bottom = 'NEW LABEL BOTTOM'
self._view.setLabels(line_top, line_bottom)
def main():
"""Main function."""
# Create an instance of `QApplication`
bincol = QApplication(sys.argv)
window = BinColUI()
window.show()
BinColCtrl(view=window)
sys.exit(bincol.exec_())
if __name__ == '__main__':
main()
Upvotes: 2
Views: 10977
Reputation: 3
I find out an answer with the help of this thread PySide6 app crashes when using QPainter.drawLine()
So modified draw_something should look like this:
def draw_something(self):
# Setup canvas for drawing
canvas = QPixmap(self.ui.label_2.size()) # Make new pixmap and set size from the size of the label
canvas.fill(Qt.GlobalColor.transparent) # Set color
self.ui.label_2.setPixmap(canvas) # Set label pixmap to THIS canvas
pm = self.ui.label_2.pixmap() # Make new instance label's pixmap
painter = QPainter(canvas) # Setup painter to use it
painter.drawLine(10, 10, 300, 200) # drawwing begins
painter.end()
self.ui.label_2.setPixmap(pm) # Set label pixmap to use this pixmap
Upvotes: 0
Reputation: 244282
In general, the painting of a QWidget (QLabel, QPushButton, etc.) should only be done in the paintEvent method as the OP seems to know. And that painting depends on the information that the widget has, for example QLabel uses a text and draws the text, OR uses a QPixmap and draws based on that pixmap. So in this case you must create a QPixmap where the line is painted, and pass that QPixmap to the QLabel to paint it.
def setLabels(self, texttop, textbot):
pixmap = QPixmap(self.label_top.size())
pixmap.fill(Qt.transparent)
qp = QPainter(pixmap)
pen = QPen(Qt.red, 3)
qp.setPen(pen)
qp.drawLine(10, 10, 50, 50)
qp.end()
self.label_top.setPixmap(pixmap)
self.label_bot.setText(textbot)
I can't have text and drawn line on the label?
As I already pointed out in the initial part of my answer: Either you paint a text or you paint a QPixmap, you can't do both in a QLabel.
Can I draw line then text on it using QPainter.drawText()
?
Yes, you can use all the methods to paint the text in the QPixmap: be creative :-). For example:
def setLabels(self, texttop, textbot):
pixmap = QPixmap(self.label_top.size())
pixmap.fill(Qt.transparent)
qp = QPainter(pixmap)
pen = QPen(Qt.red, 3)
qp.setPen(pen)
qp.drawLine(10, 10, 50, 50)
qp.drawText(pixmap.rect(), Qt.AlignCenter, texttop)
qp.end()
self.label_top.setPixmap(pixmap)
self.label_bot.setText(textbot)
Upvotes: 5