我发现QTabWidget
在重绘孩子方面表现出一种非常奇怪的行为。以下代码是我为观察此问题而创建的最小示例。
假设我有一个自定义小部件(绘图),它具有昂贵的绘制事件hadler。所以我需要尽量减少重新绘制的次数。但问题是如果这个绘图小部件在QTabWidget中,它会收到许多不必要的重绘请求,作为对其他一些完全不相关的小部件(在下面的示例中 - 按钮和标签)的更改的响应。
在示例的最后,您可以更改变量withTabWidget
。如果设置为True
,则每次按下按钮时都会重新绘制图形(即图形中的数字会增加)。如果设置为False
,则按下按钮时不会重新绘制图形(图形中的数字保持不变),这是我需要的正确行为。但显然,我还需要在我的应用布局中使用选项卡小部件......
任何想法如何使标签窗口小部件正常工作,没有不必要的重新绘制?
注意:Qt 4.8.4(在32位和64位上测试),PySide 1.2.1。,Windows 7
import sys
from PySide import QtGui
class MyDrawing(QtGui.QLabel):
# drawing is a widget which has user defined paint event handler
# the painting can be costly so we must avoid unnecessary repainting
repaintCount = 0
def paintEvent(self, event):
# a very simple example which count ...
# the number of times the paintEvent was executed
self.repaintCount += 1
painter = QtGui.QPainter(self)
painter.drawText(10, 10, str(self.repaintCount))
class MyContainer(QtGui.QWidget):
def __init__(self, parent=None):
super(MyContainer, self).__init__(parent)
layout = QtGui.QHBoxLayout(self)
# there is a button ...
self.button = QtGui.QPushButton("Press me.")
self.button.setCheckable(True)
self.button.pressed.connect(self.onButtonPressed)
layout.addWidget(self.button)
# .. and a label ...
self.label = QtGui.QLabel()
layout.addWidget(self.label)
# ... and a drawing
self.drawing = MyDrawing()
layout.addWidget(self.drawing)
def onButtonPressed(self):
# pressing button only changes the label
# it does not change the drawing
# so drawing should not be repainted
# but when the container is inside QTabWidget it IS repainted
self.label.setText(str(self.button.isChecked()))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
form = QtGui.QMainWindow()
# change this True/False!!!
withTabWidget = True
# True = problem: MyDrawing IS repainted when button1 is pressed
# False = OK: MyDrawing IS NOT repainted when button1 is pressed
if withTabWidget:
tabWidget = QtGui.QTabWidget()
tabWidget.addTab(MyContainer(), "Tab1")
form.setCentralWidget(tabWidget)
else:
form.setCentralWidget(MyContainer())
form.show()
result = app.exec_()
sys.exit(result)
更新:通过跟踪QTabWidget上的事件,我发现,当标签被更改时,会在QTabWidget中插入一些动画对象(添加子项)。 QTabWidget通过重新绘制它覆盖的整个区域来响应。这与其他窗口小部件类型不同,当插入动画对象时,它不会重绘其整个区域。不幸的是,我仍然没有解决方法。也许我会不惜一切代价制作我自己的TabWidget。
Update2:另一个有趣的方面是,当我使用QTabWidget启动上面的示例应用程序时,绘图中绘制的数字是2.当我在没有QTabWidget的情况下启动它时,数字是1.所以它是另一个示例不必要的重新粉刷。