在 PyQt5 和 PySide2 中覆盖 paintEvent
Overriding paintEvent in PyQt5 and PySide2
我使用 PyQt 和 PySide 有一段时间了。今天我偶然发现了一个奇怪的行为:重新实现 paintEvent 似乎在 Python 版本的 Qt5 中不起作用。我在 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()
因此,我们只是测试是否正在调用 paintEvent(通过在调用时引发 AssertionError)。
一旦我们将另一个小部件添加到 TagWidget 所在的同一布局,paintEvent 将不再有效。
太奇怪了。感谢帮助。
paintEvent()
在需要重新绘制时被调用,如果小部件具有 size(0, 0)
,或者大小无效或被隐藏,则不会调用该方法,这就是您的情况,使用布局时,默认情况下它将采用 sizeHint()
的大小,默认情况下 QWidget sizeHint()
是 QSize(-1, -1)
因此不需要绘制。
所以解决办法就是设置一个合适的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)
我已经用 PyQt4
和 PySide
试过了,同样的问题发生了,所以问题不是 Qt,而是这个例子。
我使用 PyQt 和 PySide 有一段时间了。今天我偶然发现了一个奇怪的行为:重新实现 paintEvent 似乎在 Python 版本的 Qt5 中不起作用。我在 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()
因此,我们只是测试是否正在调用 paintEvent(通过在调用时引发 AssertionError)。
一旦我们将另一个小部件添加到 TagWidget 所在的同一布局,paintEvent 将不再有效。
太奇怪了。感谢帮助。
paintEvent()
在需要重新绘制时被调用,如果小部件具有 size(0, 0)
,或者大小无效或被隐藏,则不会调用该方法,这就是您的情况,使用布局时,默认情况下它将采用 sizeHint()
的大小,默认情况下 QWidget sizeHint()
是 QSize(-1, -1)
因此不需要绘制。
所以解决办法就是设置一个合适的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)
我已经用 PyQt4
和 PySide
试过了,同样的问题发生了,所以问题不是 Qt,而是这个例子。