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

I can't test on a Mac, but I'll try to make a few suggestions which could help solve your issues.

Firstly, if you use a modal progress dialog, there's no need to call processEvents(), as the dialog will handle this itself.

Secondly, this line in your code:

    progress.setValue(lineNumber + 1)

is problematic, because to quote the Qt docs:

For the progress dialog to work as expected, you should initially set this property to 0 and finally set it to QProgressDialog::maximum(); you can call setValue() any number of times in-between.

so you should either call progress.setValue(0) before the loop, or just avoid adding the offset altogether. Also, on the final iteration, lineNumber + 1 will equal the maximum, which will reset the dialog at that point (unless autoReset has been set to False). It is for this reason that the Qt example calls setValue(maximum) after the loop has completed.

Finally, there is no problem with calling destroy() or deleteLater() after you've finished with the progress dialog - in fact, it's a good idea. When you pass self to the QProgressDialog constructor, it will become the parent of the dialog and keep a reference to it. So, unless you explicitly delete it, a new child dialog (plus all it's child objects) will be added every time you call the function that uses it (which could potentially waste a lot of memory).

Here's a demo script that may be improvement:

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 回答