【问题标题】:Carcass of QProgressDialog lingers - sometimesQProgressDialog 的尸体徘徊 - 有时
【发布时间】:2012-11-28 05:59:31
【问题描述】:
    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。

我做错了吗?

【问题讨论】:

  • 请不要把两个无关的问题合二为一。您应该将有关进度条的部分作为单独的问题发布。
  • @satuon。这里肯定没有两个不相关的问题,所以我已经回滚了你的编辑。无需赘述,进度对话框中的setValue() 函数所做的很多不仅仅是更新进度条小部件。

标签: python qt pyqt pyside


【解决方案1】:

我无法在 Mac 上进行测试,但我会尝试提出一些可以帮助您解决问题的建议。

首先,如果您使用模态进度对话框,则无需调用processEvents(),因为对话框会自行处理。

其次,代码中的这一行:

    progress.setValue(lineNumber + 1)

是有问题的,因为要引用Qt docs:

要使进度对话框按预期工作,您应该最初将此属性设置为 0,然后最后将其设置为 QProgressDialog::maximum();您可以在中间调用 setValue() 任意次数。

所以你应该在循环之前调用progress.setValue(0),或者完全避免添加偏移量。此外,在最后一次迭代中,lineNumber + 1 将等于最大值,这将在该点出现reset 对话框(除非autoReset 已设置为 False)。正是出于这个原因,Qt 示例在循环完成后调用setValue(maximum)

最后,在完成进度对话框后调用destroy()deleteLater() 没有问题——事实上,这是个好主意。当您将self 传递给 QProgressDialog 构造函数时,它将成为对话框的父级并保留对它的引用。因此,除非您明确删除它,否则每次调用使用它的函数时都会添加一个新的子对话框(以及它的所有子对象)(这可能会浪费大量内存)。

这是一个可能需要改进的演示脚本:

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_())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-30
    • 1970-01-01
    • 2011-12-02
    • 2013-01-09
    相关资源
    最近更新 更多