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

Performance 如何在PyQt中调整小部件大小时禁用多个自动重绘?,performance,qt,pyqt,pyqt4,qpainter,Performance,Qt,Pyqt,Pyqt4,Qpainter,我有一个PyQt4程序,其中的小部件的内容重绘速度非常慢(这没关系,因为我的任务)。当我试图调整这些小部件的大小时,程序多次试图在鼠标未释放时重新绘制。那是很多冷冻食品 我想禁用自动重绘,并将PyQt配置为仅在释放鼠标时重绘所有小部件(这意味着每次重绘仅发生一次) 怎么做 Edit1.我将非常简单地看到它,如下所示:您拖动行,当您拖动时,所有小部件都会站立。当您发布它时,小部件会重新绘制。但我不确定PYQT4中是否有可能。首先,我建议您确认,如果您使用的是使用小部件的自定义绘制事件,那么在每个事

我有一个PyQt4程序,其中的小部件的内容重绘速度非常慢(这没关系,因为我的任务)。当我试图调整这些小部件的大小时,程序多次试图在鼠标未释放时重新绘制。那是很多冷冻食品

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

怎么做


Edit1.我将非常简单地看到它,如下所示:您拖动行,当您拖动时,所有小部件都会站立。当您发布它时,小部件会重新绘制。但我不确定PYQT4中是否有可能。

首先,我建议您确认,如果您使用的是使用小部件的自定义绘制事件,那么在每个事件中,您不会做太多的工作,而是简单地寻找一个创可贴解决方案。如果是这种情况,请尝试找到一种缓存或减少工作量的方法。否则

是否绘制不透明由平台的窗口管理器决定。据我所知,没有一个简单的属性来切换此功能。类似于此的内容仅在释放控制柄后才存在于to draw上

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

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_()
您会注意到,在快速调整主窗口大小时,自定义小部件不会发生更新,因为我们在调整大小事件中已将其关闭。QTimer试图每100毫秒触发一次,以执行更新并自行停止。但每次发生另一个调整大小事件时,它都会重新启动计时器。其效果是计时器将继续重置。使更新处于禁用状态,直到出现延迟

试着按住鼠标,调整一点大小,等待,然后再调整一些大小。即使在鼠标按下但未调整大小时,也应进行更新。调整延迟以适应。您可以通过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
来监视其他事件,如移动。

这是自定义绘制事件的结果还是这些默认小部件?@jdi,主窗口上的默认小部件。例如,假设我将尝试从QTreeWidget调整到QListWidget,但QTreeWidget只会绘制可见的项目。你有大量的自定义单元格小部件吗?@jdi,我只是想告诉你它是默认的小部件,不管具体是哪个。我问这个问题的原因是,如果你在加载一个带有一堆小部件的视图,那将导致性能问题。但我知道你在寻找一个通用的解决方案。下面我的回答是关于处理调整大小事件的。好吧,感谢您的提交,这是一个很有帮助的解决方法!但仍然存在一些问题。首先,由于某些原因,您的示例在几次“实际更新”(主窗口移动)后暂停。然后它看起来像这样:只显示垃圾。第二,您的变通方法仅对主窗口移动有帮助。这很好,但窗口移动只是重新绘制的情况之一。还有QSplitter移动和QDockWidget移动,这似乎正在使用它。但不幸的是,正是这两个我最需要的:(这不是主窗口特有的。它可以用于任何QWidget。在这种情况下,您只是在观看调整大小事件。没有全局不透明的调整大小选项。@mivulf:对不起。我在其中留下了一行不应该出现的代码。我删除了
processEvents
调用。这只是为了测试,对我来说也是崩溃的。)l、 在这一点上它不应该被锁定。如果您需要查看使用事件过滤器的实用程序QObject的示例,请告诉我!非常感谢!它工作得非常好!现在我很高兴。但我不能放弃投票,因为我还没有足够的声誉。谢谢!这正是我今天需要的:-)