我开发了一个 GUI,用于从文件中提取一些数据。这个过程需要很长时间。在程序处理外部文件(使用 subprocess.Popen)期间,主 GUI 将不会响应(如预期)。我想向用户添加一 strip 有振荡进度条的消息,让他知道程序正在运行,并且可以坚持下去。
我将进度条实现为 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()
最佳答案
这是解决此问题的一种庸医方法。
如果你想以正确的方式做到这一点,你应该将 while 循环放在 QThread 内部, 并使用 Signal 和 slot 来更新 QProgressbar。
但这暂时可以解决您的问题。
缺少的部分是,
- 设置进度条的最大值setMaximum(value)
- 添加更新进度条的代码 setValue(value)
- 使用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)
#
#------------------------------------------------------------------------------
关于python - PyQt4 中的进度条问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10587971/