3
    progress = QtGui.QProgressDialog("Parsing Log", "Stop", 0,numberOfLinesInFile , self)
    progress.setWindowModality(QtCore.Qt.WindowModal)

    for lineNumber, line in enumerate(file):
        # yield a bit to the Qt UI handler
        QtGui.QApplication.processEvents()
        progress.setValue(lineNumber + 1) # lineNumber is zero-based so need the plus one to match the more literal numberOfLinesInFile
        if progress.wasCanceled():
            progressWasCancelled = True
            break


        # ...read and parse lines from file (20mb takes ~10 seconds)


    # crank the progress bar through to completion to get rid of it
    # this seems to forgo the opportunity to use progress.wasCanceled() subsequently?
    progress.setValue(numberOfLinesInFile)


    if not progressWasCancelled:
        self.updateTable(self.requestRoster)

この後、進行状況ダイアログがキャンセルされたかどうかに関係なく、進行状況ダイアログは非表示になります (スライドしてツールバーに戻ります)。しかし、アプリケーション (Mac では「コマンド タブ」) を切り替えてからアプリケーションに戻ると、メイン アプリケーション ウィンドウの前に QProgressDialog のゴーストが表示されます。プログレス バーは 100% で、停止ボタンは青色ですが、点滅していません。無反応です。アプリケーション ウィンドウを移動すると、ウィンドウが消えます。

progress.setValue(numberOfLinesInFile) の後に progress.destroy() を呼び出すと、役立つようです。しかし、ドキュメントから例をコピーして噛まれるのは心配なようで、destroy() の影響はわかりません。

私はPySideを使用していましたが、PyQtに切り替えても同じでした。

また、progress.setValue(numberOfLinesInFile)の後続の読み取りでprogress.wasCancelled()false が返されることがあります (ただし、true が返されることもあります)。これが、独自の を設定する理由ですprogressWasCancelled。そのランダム性は気がかりです。

私は Mac 10.6.8、Qt 4.8.2、Python 2.7 を使用しています。PySide 1.1.0 と PyQt 4.9.4 で試しました。

私はこれをすべて間違っていますか?

4

1 に答える 1

5

Mac でテストすることはできませんが、問題の解決に役立ついくつかの提案を試みます。

まず、モーダルプログレス ダイアログを使用する場合processEvents()、ダイアログ自体がこれを処理するため、 を呼び出す必要はありません。

次に、コード内の次の行:

    progress.setValue(lineNumber + 1)

Qt docsを引用するため、問題があります:

進行状況ダイアログが期待どおりに機能するには、最初にこのプロパティを 0に設定し、最後に QProgressDialog::maximum() に設定する必要があります。その間に何度でも setValue() を呼び出すことができます。

progress.setValue(0)そのため、ループの前に呼び出すか、オフセットを完全に追加しないようにする必要があります。また、最後の反復でlineNumber + 1は最大値に等しくなり、その時点でダイアログがリセットされます ( autoResetが False に設定されていない場合)。ループが完了したsetValue(maximum) に Qt の例が呼び出されるのはこのためです。

destroy()最後に、呼び出しや進行状況ダイアログの終了後に問題はありませんdeleteLater()。実際、これは良い考えです。QProgressDialog コンストラクターに渡すselfと、ダイアログの親になり、それへの参照を保持します。したがって、明示的に削除しない限り、それを使用する関数を呼び出すたびに、新しい子ダイアログ (およびそのすべての子オブジェクト) が追加されます (大量のメモリを浪費する可能性があります)。

改善される可能性のあるデモスクリプトを次に示します。

import sys, time
from PyQt4 import QtGui, QtCore

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.button = QtGui.QPushButton('Test', self)
        self.button.clicked.connect(self.handleButton)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.button)

    def handleButton(self):
        file = range(30)
        numberOfLinesInFile = len(file)
        progressWasCancelled = False
        progress = QtGui.QProgressDialog(
            "Parsing Log", "Stop", 0, numberOfLinesInFile, self)
        progress.setWindowModality(QtCore.Qt.WindowModal)
        progress.setMinimumDuration(0)
        for lineNumber, line in enumerate(file):
            progress.setValue(lineNumber)
            if progress.wasCanceled():
                progressWasCancelled = True
                break
            time.sleep(0.05)
        progress.setValue(numberOfLinesInFile)
        print 'cancelled', progress.wasCanceled(), progressWasCancelled
        progress.deleteLater()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())
于 2012-11-27T21:59:31.383 に答える