2012-05-14 3 views
1

파일에서 일부 데이터를 추출하는 데 사용되는 GUI를 개발했습니다. 이 프로세스는 오랜 시간이 걸립니다. 프로그램이 (subprocess.Popen을 사용하여) 외부 파일을 처리하는 동안 주 GUI는 예상대로 응답하지 않습니다. 나는 진동 진행 바를 가진 메시지를 사용자에게 보내서 프로그램이 작동하고 있고 거기에 매달려 있음을 알리고 싶었다. 진도 표시 줄을 QDialog로 구현 한 다음 긴 프로세스를 호출하기 전에 호출합니다. [dialog.exec_()] 메소드를 사용하여 진행률 막대를 호출하면 프로그램은 대화 상자의 결과 인 내 응답을 기다립니다. 대화 상자를 닫으면 프로그램은 계속 진행하려는 메시지없이 계속 진행됩니다. [dialog.show()] 메소드를 사용하면, 진행 막대가 있어야하는 빈 흰색 창이 나타납니다.
여러 변형을 시도했지만 성공하지 못했습니다.PyQt4의 진행 표시 줄 문제

내가 사용하고 있습니다 :

여기
Python 2.7.2 
PyQt4: 4.9.1 
Windows 7 

문제를 보여주는 샘플 코드입니다. dialog.exec()와 dialog.show() 사이를 전환하여 문제를 데모하십시오. LongProcess가 완료 될 때까지 당신의 GUI를 실행하는 매우 동일한 스레드를 잠글 것입니다 메인 스레드를 통해 반복되는


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

답변

2

이 문제를 해결할 수있는 방법입니다.

올바른 방법으로 작업하려면 QThread 내부에 루프를 넣고 을 입력하고 신호 및 슬롯을 사용하여 QProgressbar를 업데이트해야합니다.

하지만 문제가 해결 될 것입니다.

누락 된 조각의 ProgressBar 의 setValue (값)를 업데이트하여 ProgressBar setMaximum (값)

  • 추가 코드의

    1. 설정, 최대 값은
    2. 의 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) 
    # 
    #------------------------------------------------------------------------------ 
    
  • 0

    에서는 ProgressBar, 따라서 당신은 업데이트를 볼 수 없습니다. 긴 프로세스를 수행하는 부분을 스레드로 처리하고 메인 스레드로 다시보고해야합니다. Take a look at this SO question

    0

    GUI 업데이트를 수행하려면 단추 슬롯에서 돌아와야합니다. 그 슬롯에 앉아 있으면 실제 (보이는) 위젯 설정이 표시되지 않도록 UI 스레드를 차단하고있는 것입니다.

    저는 파이썬에 익숙하지 않지만 백그라운드에서 프로세스를 실행하는 Qt 방식 (사용자 인터페이스를 차단하지는 않습니다)은 QProcess을 사용합니다. QProcess 인스턴스에는 하위 프로세스의 상태 변경을 알리는 신호와 입력 및 출력 스트림을 처리하는 메소드가 있습니다. 그 점을 살펴보면 더 많은 유연성을 얻을 수 있습니다.

    0

    은 GUI 스레드에서 실행됩니다 on_pushButton_clicked 방법으로 모든 일을 (특히,., IMO, 아주 좋은 일이다 전혀 스레딩을 처리 할 필요가 없습니다), 따라서 동결 gui. QThread으로 이동하십시오. 및 read this.