2017-12-19 13 views
0

원격으로 업데이트되는 모달 비 차단 진행 창 (QProgressDialog 사용)이 필요한 간단한 프로그램이 있습니다. SIZE은 단순히 QProgressDialog의 최대 값을 제어합니다. 즉PyQt QProgressDialog가 빈 흰색 창으로 표시됩니다.

enter image description here

는, 윈도우가 완전히 흰색이며, 디스플레이 텍스트가 : 나는 4 이하의 값을 가지도록 설정할 경우, 윈도우는 작업의 전체 기간 동안 다음과 같다 진행률 표시 줄도 없습니다. 내가 5 이상으로 SIZE의 값을 설정하면 화면이 제대로 작동하지만 단지 2-3 첫 번째 반복 후 :

enter image description here

import sys, time 
from PyQt5.QtWidgets import * 
from PyQt5.QtCore import * 
from PyQt5.QtGui import * 

SIZE = 5 

def doGenerate(setValue): 
    for x2 in range(SIZE): 
     time.sleep(1) 
     setValue(x2 + 1) 
    print('Done') 


class MainMenu(QMainWindow): 
    def __init__(self): 
     super().__init__() 

     self.genAudioButton = QPushButton('Generate', self) 
     self.genAudioButton.clicked.connect(self.generate) 

     self.setCentralWidget(self.genAudioButton) 
     self.show() 

    def generate(self): 
     try: 
      progress = QProgressDialog('Work in progress', '', 0, SIZE, self) 
      progress.setWindowTitle("Generating files...") 
      progress.setWindowModality(Qt.WindowModal) 
      progress.show() 
      progress.setValue(0) 
      doGenerate(progress.setValue) 
     except Exception as e: 
      errBox = QMessageBox() 
      errBox.setWindowTitle('Error') 
      errBox.setText('Error: ' + str(e)) 
      errBox.addButton(QMessageBox.Ok) 
      errBox.exec() 
      return 

if __name__ == '__main__': 
    app = QApplication(sys.argv) 
    ex = MainMenu() 
    ret = app.exec_() 
    sys.exit(ret) 

나중에

enter image description here

을 이 문제의 원인은 무엇이며 어떻게 해결할 수 있습니까?

또한 완전히 대신 여전히이 작업을 취소 빈 버튼이있는의, 취소 버튼을 제거하는 방법은 무엇입니까? PyQt4 문서 (나는 PyQt5를 사용하고 있습니다)는 빈 문자열이이 결과를 얻었음을 나타내고 Qt5의 C++ 문서는 같은 것을 나타냅니다. 그러나 분명히 여기서는 작동하지 않습니다. PyQt5에 대한 독립형 문서를 찾지 못했습니다.

답변

1

GUI는 app.exec_()을 통해 메인 루프를 구현합니다.이 루프는 이벤트 검사, 신호 검사, 일부 기능 호출 등과 같은 작업을 수행하는 데 사용됩니다. 따라서 우리가 루프를 중단하면 관찰 한 것과 같은 예기치 않은 동작이 발생할 수 있습니다. 귀하의 경우 sleep()에 사용할 수 없습니다 차단 기능이며, Qt를 그것에 대안을 제공하며, 그 중 하나가 QEventLoopQTimer와 함께 사용하는 것입니다 : 당신은 취소 버튼을 표시하지 않도록하려면

def doGenerate(setValue): 
    for x2 in range(SIZE): 
     loop = QEventLoop() 
     QTimer.singleShot(1000, loop.quit) 
     loop.exec_() 
     setValue(x2 + 1) 
    print('Done') 

을, 당신은 아무도 통과하지해야합니다 당신은 당신이 스레드를 통해 수행해야 gTTS를 사용하려면

progress = QProgressDialog('Work in progress', None, 0, SIZE, self) 

을, Qt는이,이 경우 내가 QRunnableQThreadPool를 사용합니다 구현하는 여러 가지 방법을 제공합니다. QMetaObject.invokeMethod을 사용하여 GUI 값을 업데이트합니다. Qt는 메인 스레드가 아닌 다른 스레드에서 GUI를 업데이트 할 수 없기 때문에 사용합니다.

import sys, time 
from PyQt5.QtWidgets import * 
from PyQt5.QtCore import * 
from PyQt5.QtGui import * 
from gtts import gTTS 


class GTTSRunnable(QRunnable): 
    def __init__(self, data, progress): 
     QRunnable.__init__(self) 
     self.data = data 
     self.w = progress 

    def run(self): 
     for i, val in enumerate(self.data): 
      text, filename = val 
      tts = gTTS(text=text, lang='en') 
      tts.save(filename) 
      QMetaObject.invokeMethod(self.w, "setValue", 
       Qt.QueuedConnection, Q_ARG(int, i+1)) 
      QThread.msleep(10) 

class MainMenu(QMainWindow): 
    def __init__(self): 
     super().__init__() 
     self.genAudioButton = QPushButton('Generate', self) 
     self.genAudioButton.clicked.connect(self.generate) 
     self.setCentralWidget(self.genAudioButton) 
     self.show() 

    def generate(self): 
     try: 
      info = [("hello", "1.mp4"), ("how are you?", "2.mp4"), ("StackOverFlow", "3.mp4")] 
      self.progress = QProgressDialog('Work in progress', '', 0, len(info), self) 
      self.progress.setWindowTitle("Generating files...") 
      self.progress.setWindowModality(Qt.WindowModal) 
      self.progress.show() 
      self.progress.setValue(0) 
      self.doGenerate(info) 
     except Exception as e: 
      errBox = QMessageBox() 
      errBox.setWindowTitle('Error') 
      errBox.setText('Error: ' + str(e)) 
      errBox.addButton(QMessageBox.Ok) 
      errBox.exec() 
      return 

    def doGenerate(self, data): 
     self.runnable = GTTSRunnable(data, self.progress) 
     QThreadPool.globalInstance().start(self.runnable) 

if __name__ == '__main__': 
    app = QApplication(sys.argv) 
    ex = MainMenu() 
    ret = app.exec_() 
    sys.exit(ret) 
+0

답장을 보내 주셔서 감사합니다. 'sleep '은 내가이 문제를 재현하는 최소한의 예제를 작성하는 것이지만, 원래의 프로그램은 실제로 sleep 대신 doGenerate 내부의 파일에 쓰고 있었다. 그건 원래의 파이썬 파일 쓰기를 통해서가 아니라, 거의 제어 할 수없는 라이브러리의 함수를 사용하는 것입니다 ([gTTS] (https://github.com/pndurette/gTTS/)의'save' 또는'write_to_fp') . 당신의 솔루션을 어떻게 적응시킬 수 있습니까? – pie3636

+1

@ pie3636 gTT를 통해 백분율을 어떻게 얻습니까? 라이브러리를 사용했는데 진행률을 알려주는 함수를 찾지 못했습니까? – eyllanesc

+0

나는 많은 수의 파일을 생성해야한다. 그래서 내가하는 일은 각 파일 다음에'files_done/total_files'로 백분율을 계산하는 것이다. 그러나 각 파일이 끝난 후 GUI를 업데이트하면 파일 쓰기가 차단되어 있기 때문에 창이 비어있는 문제가 발생합니다. – pie3636

관련 문제