【问题标题】:Progress Bar issues in PyQt4PyQt4 中的进度条问题
【发布时间】:2012-05-15 01:48:45
【问题描述】:

我开发了一个 GUI,用于从文件中提取一些数据。这个过程需要很长时间。在程序处理外部文件期间(使用 subprocess.Popen),主 GUI 将不会响应(如预期的那样)。我想向用户添加一条带有摆动进度条的消息,让他知道程序正在运行,并且只是挂在那里。 我将进度条实现为 QDialog,然后在调用长进程之前调用它。如果我使用 [dialog.exec_()] 方法调用进度条,那么程序会等待我的响应,即对话的结果。如果我关闭对话框,程序将继续运行,而不会显示我想要显示的进度消息。如果我使用 [dialog.show()] 方法,那么我看到的只是一个空白窗口,进度条应该在该窗口。
我对此尝试了多种变体,但没有成功。

我正在使用:

Python 2.7.2
PyQt4: 4.9.1
Windows 7

这是显示问题的示例代码。在 dialog.exec() 和 dialog.show() 之间切换以演示问题。


import sys
import time
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import pyqtSignature

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

class LongProcess(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(LongProcess, self).__init__(parent)
        self.setup(self)

    def setup(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(255, 208)
        MainWindow.setMinimumSize(QtCore.QSize(300, 208))
        MainWindow.setMaximumSize(QtCore.QSize(300, 208))
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.textEdit = QtGui.QTextEdit(self.centralwidget)
        self.textEdit.setObjectName(_fromUtf8("textEdit"))
        self.verticalLayout.addWidget(self.textEdit)
        self.pushButton = QtGui.QPushButton(self.centralwidget)
        self.pushButton.setObjectName(_fromUtf8("pushButton"))
        self.verticalLayout.addWidget(self.pushButton)
        MainWindow.setCentralWidget(self.centralwidget)

        MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
        self.textEdit.setHtml(QtGui.QApplication.translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
                                                           "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
                                                           "p, li { white-space: pre-wrap; }\n"
                                                           "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n"
                                                           "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:8pt;\">We want to run a long process in the background (calling a subprocess) and use an oscillating progress bar to show that the process is running. </span></p>\n"
                                                           "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;\"><br /></p>\n"
                                                           "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:8pt;\">When long process ends, we will close the oscillating progress bar. </span></p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton.setText(QtGui.QApplication.translate("MainWindow", "Run Long Process", None, QtGui.QApplication.UnicodeUTF8))
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    @pyqtSignature("")
    def on_pushButton_clicked(self):
        '''
            Simulate some long process to be performed.
            Before Long Process starts, show an oscillating progress bar to
            indiate process is running in background. 
        '''
        dialog = QtGui.QDialog()    
        progressBar = Ui_porcessProgress()
        progressBar.setupUi(dialog)
        dialog.show()
#        dialog.exec_()

        start = time.time()
        diff = 0
        while diff < 10:
            end = time.time()
            diff = end - start
            print (diff)

class Ui_porcessProgress(object):
    def setupUi(self, porcessProgress):
        porcessProgress.setObjectName(_fromUtf8("porcessProgress"))
        porcessProgress.setWindowModality(QtCore.Qt.ApplicationModal)
        porcessProgress.resize(329, 81)
        porcessProgress.setMinimumSize(QtCore.QSize(329, 81))
        porcessProgress.setMaximumSize(QtCore.QSize(329, 81))
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/WFT/wftlogo2.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        porcessProgress.setWindowIcon(icon)
        porcessProgress.setModal(True)
        self.verticalLayout = QtGui.QVBoxLayout(porcessProgress)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.label = QtGui.QLabel(porcessProgress)
        self.label.setObjectName(_fromUtf8("label"))
        self.verticalLayout.addWidget(self.label)
        self.porcessProgressBar = QtGui.QProgressBar(porcessProgress)
        self.porcessProgressBar.setMaximum(0)
        self.porcessProgressBar.setProperty("value", 10)
        self.porcessProgressBar.setTextVisible(False)
        self.porcessProgressBar.setObjectName(_fromUtf8("porcessProgressBar"))
        self.verticalLayout.addWidget(self.porcessProgressBar)
        porcessProgress.setWindowTitle(QtGui.QApplication.translate("porcessProgress", "Please wait...", None, QtGui.QApplication.UnicodeUTF8))
        self.label.setText(QtGui.QApplication.translate("porcessProgress", "Time History data extraction from ODB file in progress...", None, QtGui.QApplication.UnicodeUTF8))
        QtCore.QMetaObject.connectSlotsByName(porcessProgress)
#
#------------------------------------------------------------------------------ 
#
def main():
    app = QtGui.QApplication(sys.argv)
    mainWindow = LongProcess()
    mainWindow.show()
    sys.exit(app.exec_())
#
#------------------------------------------------------------------------------ 
#
if __name__ == "__main__":
    main()

【问题讨论】:

    标签: python pyqt4


    【解决方案1】:

    这是解决此问题的一种古怪方法。

    如果你想这样做,你应该把while循环放在QThread里面, 并使用 Signal 和 slot 更新 QProgressbar。

    但这暂时可以解决您的问题。

    缺少的部分是,

    1. 设置progressBar的最大值setMaximum(value)
    2. 添加代码更新进度条setValue(value)
    3. 使用 QApplication.processEvents() 强制事件处理

    快速修复:

    #Add QApplication on top #################
    from PyQt4.QtGui import QApplication
    ##########################################
    def on_pushButton_clicked(self):
            '''
                Simulate some long process to be performed.
                Before Long Process starts, show an oscillating progress bar to
                indiate process is running in background. 
            '''
            dialog = QtGui.QDialog()    
            progressBar = Ui_porcessProgress()
            progressBar.setupUi(dialog)
            dialog.show()
            #dialog.exec_()
    
            start = time.time()
            diff = 0
            while diff < 10:
                end = time.time()
                diff = end - start
    
    
                ################################################### 
                #add routine to update progressBar value
                progressBar.porcessProgressBar.setValue(diff)
                QApplication.processEvents()
                #add routine to update progressBar value 
                ###################################################
    
    
                print (diff)
    
    class Ui_porcessProgress(object):
        def setupUi(self, porcessProgress):
            porcessProgress.setObjectName(_fromUtf8("porcessProgress"))
            porcessProgress.setWindowModality(QtCore.Qt.ApplicationModal)
            porcessProgress.resize(329, 81)
            porcessProgress.setMinimumSize(QtCore.QSize(329, 81))
            porcessProgress.setMaximumSize(QtCore.QSize(329, 81))
            icon = QtGui.QIcon()
            icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/WFT/wftlogo2.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
            porcessProgress.setWindowIcon(icon)
            porcessProgress.setModal(True)
            self.verticalLayout = QtGui.QVBoxLayout(porcessProgress)
            self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
            self.label = QtGui.QLabel(porcessProgress)
            self.label.setObjectName(_fromUtf8("label"))
            self.verticalLayout.addWidget(self.label)
            self.porcessProgressBar = QtGui.QProgressBar(porcessProgress)
    
            ###########################################
            ####Set max value of progress bar
            self.porcessProgressBar.setMaximum(10)
            ############################################
    
            self.porcessProgressBar.setProperty("value", 10)
            self.porcessProgressBar.setTextVisible(False)
            self.porcessProgressBar.setObjectName(_fromUtf8("porcessProgressBar"))
            self.verticalLayout.addWidget(self.porcessProgressBar)
            porcessProgress.setWindowTitle(QtGui.QApplication.translate("porcessProgress", "Please wait...", None, QtGui.QApplication.UnicodeUTF8))
            self.label.setText(QtGui.QApplication.translate("porcessProgress", "Time History data extraction from ODB file in progress...", None, QtGui.QApplication.UnicodeUTF8))
            QtCore.QMetaObject.connectSlotsByName(porcessProgress)
    #
    #------------------------------------------------------------------------------ 
    

    【讨论】:

      【解决方案2】:

      您需要从按钮槽返回以进行 GUI 更新。如果您坐在那个插槽中,您将阻塞 UI 线程,因此不会显示实际(可见)小部件设置。

      我不熟悉 Python,但 Qt 在后台运行进程的方式(不会阻塞你的 UI)是使用QProcess。 QProcess 实例具有通知子进程状态更改的信号,以及处理输入和输出流的方法。 您可能想研究一下,它将提供更大的灵活性。
      (特别是,您根本不需要处理线程,这在 IMO 中是一件好事。)

      【讨论】:

        【解决方案3】:

        您在on_pushButton_clicked 方法中所做的一切都将在 gui 线程中执行,因此冻结 gui。只需将其移至QThread。和read this

        【讨论】:

          【解决方案4】:

          通过主线程循环的 ProgressBar 将锁定运行 GUI 的同一线程,因此在 LongProcess 完成之前您不会看到任何更新。您需要对执行长过程的部分进行线程化并报告回主线程。 Take a look at this SO question

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多