AmmarYasir
AmmarYasir

Reputation: 102

Integrating QPainter in PyQt GUI

I'm trying to use QPainter-made object along with native widgets of PyQt in one layout and having a difficulty doing so.

I've tried using addWidget() to add it to the layout but no luck.

class window(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(600, 500)
        self.setWindowTitle('GUI 2.0')

        #LCD
        self.lcd = QLCDNumber()
        self.lcd.setFixedHeight(100)

        #Slider
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setMaximum(40)
        self.slider.setMinimum(0)
        self.slider.valueChanged.connect(self.progress)

        #Push button
        pb = QPushButton('Button', self)
        pb.clicked.connect(self.button)

        #Progress Bar
        self.pbar = QProgressBar(self)
        self.pbar.setGeometry(30, 40, 200, 25)
        self.pbar.setTextVisible(False)

        #Qpainter
        painter = QPainter()
        painter.setPen(QPen(Qt.black, 5, Qt.SolidLine))
        painter.setBrush(QBrush(Qt.green, Qt.DiagCrossPattern))
        painter.drawRect(100, 15, 400,200)

        #Grid Layout 
        layout = QGridLayout()
        layout.addWidget(self.lcd, 1, 1)
        layout.addWidget(self.slider, 2, 1)
        layout.addWidget(pb, 2, 2)
        layout.addWidget(self.pbar, 0, 1)
        layout.addWidget(painter) # doesn't work!

        self.setLayout(layout)

My aim is for something like this where the slider will eventually change the water level in the tank and the button will reset the slider value and therefore empty the tank:

Water Tank

Water Tank

Whereas I have something like this:

Self-Made

How can I add the painter object to the layout?

Upvotes: 3

Views: 1833

Answers (1)

eyllanesc
eyllanesc

Reputation: 244282

QPainter is not a widget but only paints on a device (QWidget, QImage, QPixmap, etc.), so in your case you must create a custom widget where in the paintEvent method the tank is painted

from PyQt5 import QtCore, QtGui, QtWidgets


class TankWidget(QtWidgets.QWidget):
    progressChanged = QtCore.pyqtSignal(float)

    def __init__(self, parent=None):
        super().__init__(parent)

        self._progress = 0.0

    @QtCore.pyqtProperty(float, notify=progressChanged)
    def progress(self):
        return self._progress

    @progress.setter
    def progress(self, p):
        if 0 <= p <= 1.0:
            self._progress = p
            self.progressChanged.emit(p)
            self.update()

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        height = self.progress * self.height()

        r = QtCore.QRect(0, self.height() - height, self.width(), height)
        painter.fillRect(r, QtGui.QBrush(QtCore.Qt.blue))
        pen = QtGui.QPen(QtGui.QColor("red"), 10)
        painter.setPen(pen)
        painter.drawRect(self.rect())

    def sizeHint(self):
        return QtCore.QSize(100, 100)


class Widget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.resize(600, 500)
        self.setWindowTitle("GUI 2.0")

        self.tank = TankWidget()
        self.progressbar = QtWidgets.QProgressBar()
        self.lcd = QtWidgets.QLCDNumber()
        self.lcd.setFixedHeight(100)
        self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal, maximum=101)
        self.button = QtWidgets.QPushButton("Button")

        self.slider.valueChanged.connect(self.on_value_changed)

        lay = QtWidgets.QGridLayout(self)
        lay.addWidget(self.tank, 0, 0, 2, 1)
        lay.addWidget(QtWidgets.QLabel("Tank", alignment=QtCore.Qt.AlignCenter), 2, 0)
        lay.addWidget(self.progressbar, 0, 1)
        lay.addWidget(self.lcd, 1, 1)
        lay.addWidget(self.slider, 2, 1)
        lay.addWidget(
            QtWidgets.QLabel(
                pixmap=QtGui.QPixmap("warning.png"), alignment=QtCore.Qt.AlignCenter
            ),
            0,
            2,
            2,
            1,
        )
        lay.addWidget(self.button, 2, 2)

        self.setFixedHeight(self.sizeHint().height())

        self.slider.setValue(40)

    @QtCore.pyqtSlot()
    def on_value_changed(self):
        progress = self.slider.value() * 1.0 / self.slider.maximum()
        self.tank.progress = progress
        self.progressbar.setValue(self.slider.value())
        self.lcd.display(self.slider.value())


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

enter image description here

Upvotes: 4

Related Questions