2017-12-19 25 views
0

私はリモートで更新されるモーダルで非ブロッキングの進捗ウィンドウ(QProgressDialogを使用)を使用したいこの簡単なプログラムを持っています。 SIZEは、単にQProgressDialogの最大値を制御します。言い換えればPyQt QProgressDialogは白い空白のウィンドウとして表示されます

enter image description here

は、窓が完全に白で表示されていないテキスト:私は4以下の値を持つようにそれを設定する場合は、ウィンドウは、アクションの全期間中にこのようになります。プログレスバーもありません。私が5以上にSIZEの値を設定した場合、表示が正しく動作しますが、唯一の2-3最初のイテレーションの後:

enter image description here

以降

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) 

これを引き起こしていると私はそれを修正する方法は?

さらに、完全に代わりまだがアクションをキャンセルし、空のボタンを有していると、キャンセルボタンを削除する方法はありますか? 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') 

を、あなたはNoneを渡す必要があります:あなたは、スレッドを通してそれを行う必要があり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'の中のファイルに書き込んでいました。これは、ネイティブのpythonファイルの書き方ではなく、私がほとんどコントロールすることのできないライブラリの関数を使用していました([gTTS](https://github.com/pndurette/gTTS/)の 'save'または' write_to_fp') 。どのように私はあなたのソリューションを適応させることができますか? – pie3636

+1

@ pie3636 gTTを使ってパーセンテージをどのように取得しますか?そのライブラリを使用していて、進捗率を教えてくれる関数が見つかりませんでしたか? – eyllanesc

+0

私はたくさんのファイルを生成しなければならないので、単純にファイルごとに 'files_done/total_files'を計算します。しかし、ファイルへの書き込みがブロックされているので、各ファイルの後にGUIを更新すると、ウィンドウが空白の問題が発生するでしょう。 – pie3636

関連する問題