简体   繁体   English

覆盖PyQt5和PySide2中的paintEvent

[英]Overriding paintEvent in PyQt5 and PySide2

I've been using PyQt and PySide for a while. 我一直在使用PyQt和PySide。 Today I stumbled upon a weird behaviour : re-implementing paintEvent does not seem to work in Python versions of Qt5. 今天我偶然发现了一个奇怪的行为:重新实现paintEvent似乎不适用于Qt5的Python版本。 I never had this problem in Qt4. 我在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). 所以,我们只是测试是否正在调用paintEvent(通过在调用时引发AssertionError)。

Once we add another widget to the same layout where TagWidget sits, the paintEvent is not effective anymore. 一旦我们将另一个小部件添加到TagWidget所在的相同布局,paintEvent就不再有效了。

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. 当需要重新绘制时调用paintEvent() ,如果窗口小部件的size(0, 0)或大小无效或者隐藏了该方法未被调用,那么在你的情况下会发生这种情况,当使用布局时它会默认情况下,取sizeHint()的大小,默认情况下,QWidget sizeHint()QSize(-1, -1) ,因此无需绘制。

So the solution is to set an appropriate sizeHint() : 所以解决方案是设置一个合适的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. 我用PyQt4PySide尝试过,同样的问题发生了,所以问题不是Qt而是特别的例子。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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