简体   繁体   中英

Overriding paintEvent in PyQt5 and PySide2

I've been using PyQt and PySide for a while. Today I stumbled upon a weird behaviour : re-implementing paintEvent does not seem to work in Python versions of Qt5. I never had this problem in Qt4.

from PySide2 import QtWidgets, QtCore, QtGui # use pyside
# from PyQt5 import QtWidgets, QtCore, QtGui # use pyqt
import sys


class TagWidget(QtWidgets.QWidget):

    def __init__(self, parent):
        super().__init__(parent)
        print("__init__")


    def paintEvent(self, e): 
        # this is called or not
        # depends (see below)
        print("paintEvent")
        raise(AssertionError)


class MyGui(QtWidgets.QMainWindow):


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

    def setupUi(self):
        self.setGeometry(QtCore.QRect(100,100,500,500))

        self.w=QtWidgets.QWidget(self)    
        self.setCentralWidget(self.w)

        self.lay = QtWidgets.QHBoxLayout(self.w)
        self.image = TagWidget(self.w)
        self.lay.addWidget(self.image)

        # return 
        # exit here, and TagWidget.paintEvent 
        # is still being called

        self.file_list = QtWidgets.QListWidget(self.w)

        # return 
        # exit here, and TagWidget.paintEvent 
        # is still being called

        self.lay.addWidget(self.file_list)

        # .. but if we reach all the way here, 
        # TagWidget.paintEvent is never called !


def main():
    app=QtWidgets.QApplication(["test_app"])
    mg=MyGui()
    mg.show()
    app.exec_()


if (__name__=="__main__"):
    main()

So, we're just testing if paintEvent is being called (by raising AssertionError when it's called).

Once we add another widget to the same layout where TagWidget sits, the paintEvent is not effective anymore.

So weird. Help appreciated.

paintEvent() is called when it is necessary to repaint, if the widget has size(0, 0) , or size invalid or is hidden that method is not called, and that is what happens in your case, when using a layout it will take the size of sizeHint() by default, by default a QWidget sizeHint() is QSize(-1, -1) and therefore no need to paint.

So the solution is to set an appropriate sizeHint() :

class TagWidget(QtWidgets.QWidget):
    def paintEvent(self, e): 
        print("paintEvent")
        raise(AssertionError)

    def sizeHint(self):
        print("default sizeHint: ", super(TagWidget, self).sizeHint())
        return QtCore.QSize(640, 480)

I've tried it with PyQt4 and PySide and the same problem happens, so the problem is not Qt but the example in particular.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM