5

コンテンツの再描画が非常に遅いウィジェットを備えたPyQt4プログラムがあります(私のタスクのため、問題ありません)。そして、これらのウィジェットのサイズを変更しようとすると、マウスが解放されていないときにプログラムが何度も再描画しようとします。それはたくさんのフリーズです。

その自動再描画を無効にし、マウスが離されたときにのみすべてのウィジェットを再描画するようにPyQtを構成したいと思います(つまり、再描画は1回のサイズ変更ごとに1回だけ行われます)。

どうやってするか?

編集1。このように、非常に簡単にわかります。線をドラッグすると、ドラッグしている間、すべてのウィジェットが立っています。リリースすると、ウィジェットが再描画されます。しかし、PyQt4でそれが可能かどうかは本当にわかりません。

4

1 に答える 1

9

まず、ウィジェットでカスタムペイントイベントを使用している場合は、各イベントで過度の作業を行わず、単にバンドエイドソリューションを探していることを確認することをお勧めします。このような場合は、作業をキャッシュまたは削減する方法を見つけてください。さもないと...

不透明に描画するかどうかの決定は、プラットフォームのウィンドウマネージャーによって行われます。私の知る限り、この機能を切り替えるための単純な属性はありません。これに似たものがQSplitter、ハンドルを離した後にのみ描画するために存在します。

回避策の1つを提供できます。それは、一定期間サイズ変更が発生しなくなるまで更新を遅らせることです。これにより、アプリケーションにペイントイベントを減らすための余裕ができます。

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ミリ秒ごとに起動しようとしています。ただし、別のサイズ変更イベントが発生するたびに、そのタイマーが再起動します。その結果、タイマーは引き続きリセットされます。遅延が発生するまで、更新を無効のままにします。

マウスを押したまま、サイズを少し変更して、しばらく待ってから、もう少しサイズを変更してみてください。マウスが下がっていても、サイズを変更していない場合でも、更新が行われるはずです。それに合わせて遅延を調整します。また、ブールフラグを使用して機能のオンとオフを制御できます。

DelayedUpdaterこの例は、引数としてQWidgetインスタンスを受け入れるQObjectだけを作成するように作り直すこともできます。次に、それ自体をそのオブジェクトのeventFilterforに設定し、そのオブジェクトを監視し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、移動などの他のイベントも監視できます。

于 2012-11-25T20:14:09.943 に答える