如何在PyQt中调整小部件大小时禁用多次自动重绘?

时间:2012-11-25 15:18:28

标签: performance qt pyqt pyqt4 qpainter

我有一个带有小部件的PyQt4程序,其内容重绘速度非常慢(因为我的任务,所以没问题)。当我试图调整这些小部件的大小时,程序试图在鼠标未释放的情况下重绘很多次。那是很多冻结。

我想禁用自动重绘并配置PyQt仅在鼠标释放时重绘所有小部件(这意味着重绘每次调整大小只发生一次)。

怎么做?

Edit1。我会很简单地看到它,就像这样:拖动线条,拖动时,所有小部件都会立即显示。当您释放它时,小部件重绘。但是我真的不确定在PyQt4中它是否可行。

1 个答案:

答案 0 :(得分:7)

首先,我建议确保如果您在小部件中使用自定义绘画事件,那么您在每个活动中都没有做太多的工作,只是寻找创可贴解决方案。如果是这种情况,请尝试找到一种缓存或减少工作的方法。否则...

绘制不透明或不透明的决定是由平台的窗口管理器决定的。据我所知,切换此功能没有简单的属性。 QSplitter上存在与此类似的内容,仅在释放句柄后绘制。

我可以提供一种解决方法,即延迟更新,直到在一段时间内没有发生调整大小之后。这将为您的应用程序提供一些喘息空间,以减少油漆事件。

from PyQt4 import QtCore, QtGui
import sys

class DelayedUpdater(QtGui.QWidget):

    def __init__(self):
        super(DelayedUpdater, self).__init__()
        self.layout = QtGui.QVBoxLayout(self)
        self.label = QtGui.QLabel("Some Text")
        self.layout.addWidget(self.label, QtCore.Qt.AlignCenter)

        self.delayEnabled = False
        self.delayTimeout = 100

        self._resizeTimer = QtCore.QTimer(self)
        self._resizeTimer.timeout.connect(self._delayedUpdate)

    def resizeEvent(self, event):
        if self.delayEnabled:
            self._resizeTimer.start(self.delayTimeout)
            self.setUpdatesEnabled(False)

        super(DelayedUpdater, self).resizeEvent(event)

    def _delayedUpdate(self):
        print "Performing actual update"
        self._resizeTimer.stop()
        self.setUpdatesEnabled(True)


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    win = QtGui.QMainWindow()
    view = DelayedUpdater()
    win.setCentralWidget(view)
    win.show()
    view.delayEnabled = True
    app.exec_()

您会注意到,当您快速调整主窗口的大小时,自定义窗口小部件不会进行任何更新,因为我们已在resize事件中将其关闭。 QTimer试图每100毫秒触发一次以执行更新并自行停止。但每次发生另一个resize事件时,它将重新启动该计时器。结果是计时器将继续重置。保持禁用更新,直到发生延迟。

尝试按住鼠标,调整一点,等待,然后再调整一些。即使您的鼠标已关闭但您没有调整大小,也应该进行更新。调整延迟以适应。并且您可以控制使用bool标志打开和关闭该功能。

也可以重新编写这个例子,使DelayedUpdater只是一个QObject,它接受一些QWidget实例作为参数。然后,它会将自己设置为该对象的eventFilter并监视其resizeEvent。这样您就不必为了添加它而继承普通小部件。您只需创建DelayedUpdater的实例,并将其用作实用程序对象来监视窗口小部件。

以下是将其作为辅助对象的示例:

class MainWindow(QtGui.QMainWindow):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.someWidget = QtGui.QWidget()
        self.setCentralWidget(self.someWidget)

        self.layout = QtGui.QVBoxLayout(self.someWidget)
        self.label = QtGui.QLabel("Some Text")
        self.layout.addWidget(self.label, QtCore.Qt.AlignCenter)

        self.delayer = DelayedUpdater(self.someWidget)


class DelayedUpdater(QtCore.QObject):

    def __init__(self, target, parent=None):
        super(DelayedUpdater, self).__init__(parent)
        self.target = target
        target.installEventFilter(self)

        self.delayEnabled = True
        self.delayTimeout = 100

        self._resizeTimer = QtCore.QTimer()
        self._resizeTimer.timeout.connect(self._delayedUpdate)

    def eventFilter(self, obj, event):
        if self.delayEnabled and obj is self.target:
            if event.type() == event.Resize:
                self._resizeTimer.start(self.delayTimeout)
                self.target.setUpdatesEnabled(False)

        return False

    def _delayedUpdate(self):
        print "Performing actual update"
        self._resizeTimer.stop()
        self.target.setUpdatesEnabled(True)

请注意,我们在主窗口内的任意窗口小部件上使用它。我们使用以下行添加延迟更新程序:

self.delayer = DelayedUpdater(self.someWidget)

DelayedUpdater监视目标窗口小部件的调整大小事件,并执行延迟更新。您可以展开eventFilter以观看其他活动,例如移动。