Как отключить многократную автоматическую перерисовку при изменении размера виджетов в PyQt?
У меня есть программа PyQt4 с виджетами, содержимое которых перерисовывается очень медленно (это нормально, из-за моих задач). И когда я пытаюсь изменить размер этих виджетов, программа пытается перерисовать много раз, пока мышь не отпущена. Это очень много заморозков.
Я хочу отключить эту автоматическую перерисовку и настроить PyQt на перерисовку всех виджетов только при отпускании мыши (что означает, что перерисовка происходит ровно один раз за одно изменение размера).
Как это сделать?
Edit1. я буду смотрите на это довольно просто, вот так: вы перетаскиваете линию, и в то время как вы перетаскиваете, все виджеты стоят. Когда вы отпустите его, виджеты перерисовываются. Но я действительно не уверен, что это возможно в PyQt4.
1 ответ:
Во-первых, я бы рекомендовал убедиться, что если вы используете пользовательские события рисования с виджетами, что вы не делаете слишком много работы в каждом событии и просто ищете решение для лейкопластыря. Если это так, попробуйте найти способ кэшировать или уменьшить объем работы. Иначе...
Решение рисовать непрозрачно или нет принимается оконным менеджером вашей платформы. Насколько я знаю, нет простого атрибута для переключения этой функции. Что-то подобное этому существует на
Я могу предложить один обходной подход, который заключается в том, чтобы отложить обновление до тех пор, пока не произойдет изменение размера в течение определенного периода времени. Это даст вашему приложению некоторую передышку, чтобы уменьшить события краски.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 мс чтобы выполнить обновление и остановить себя. Но каждый раз, когда происходит другое событие изменения размера, он перезапускает этот таймер. В результате таймер будет продолжать сбрасываться. оставляя обновления отключенными, пока не произойдет задержка.
Попробуйте, удерживая нажатой кнопку мыши, немного изменить размер, подождите и измените размер еще немного. Обновление должно произойти, даже если ваша мышь не работает, но вы не меняете размер. Отрегулируйте задержку, чтобы удовлетворить. И у вас есть контроль над включением и выключением функции с помощью 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, Чтобы также наблюдать за другими событиями, такими как перемещение.
Comments