关于python:在PyQt5和PySide2中覆盖paintEvent

Overriding paintEvent in PyQt5 and PySide2

我使用PyQt和PySide已有一段时间了。今天,我偶然发现了一个奇怪的行为:重新实现paintEvent似乎在Qt5的Python版本中不起作用。我在Qt4中从未遇到过此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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()

因此,我们只是测试是否调用paintEvent(通过在调用它时引发AssertionError)。

一旦将另一个小部件添加到TagWidget所在的相同布局中,paintEvent将不再有效。

太奇怪了。感谢帮助。


如果需要重绘,则

paintEvent()会被调用,如果小部件具有size(0, 0)或大小无效或被隐藏,则不会调用该方法,这就是您的情况,使用布局时会默认情况下采用sizeHint()的大小,默认情况下QWidget sizeHint()QSize(-1, -1),因此无需绘制。

因此解决方案是设置适当的sizeHint()

1
2
3
4
5
6
7
8
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)

我用PyQt4PySide进行了尝试,并且发生了相同的问题,所以问题不是Qt,而是示例。