2017-06-28 9 views
0

30秒以上かかるデータをロードしようとしています。この間、私はユーザーに "Loading ..."、次に "Loading .."、 "Loading ..."、そして "Loading"という小さなGUIを見てほしい。私はいくつかの読書をして、私は別のスレッドでこれを入れなければならないと思う。私は解決策を示唆し、同様の問題を持っていた人を見つけたこの権利スポットで:私はテスト機能PyQt5スレッドGUIが動作しない

def test(self): 
    tmp = InfoMessage() 

    while True: 
     print(1) 

とInfoMessage機能を持っているファイルの下部に

t = threading.Thread(target=self.test) 
t.daemon = True 
t.start() 

from PyQt5 import uic, QtCore, QtGui, QtWidgets 
import sys 

class InfoMessage(QtWidgets.QDialog): 
    def __init__(self, msg='Loading ', parent=None): 
     try: 
      super(InfoMessage, self).__init__(parent) 
      uic.loadUi('ui files/InfoMessage.ui',self) 

      self.setWindowTitle(' ') 

      self.o_msg = msg 
      self.msg = msg 
      self.info_label.setText(msg) 
      self.val = 0 

      self.timer = QtCore.QTimer() 
      self.timer.setInterval(500) 
      self.timer.timeout.connect(self.update_message) 
      self.timer.start() 

      self.show() 
     except BaseException as e: 
      print(str(e)) 

    def update_message(self): 
     self.val += 1 
     self.msg += '.' 

     if self.val < 20: 
      self.info_label.setText(self.msg) 
     else: 
      self.val = 0 
      self.msg = self.o_msg 

     QtWidgets.QApplication.processEvents() 

def main(): 
    app = QtWidgets.QApplication(sys.argv)  # A new instance of QApplication 
    form = InfoMessage('Loading ')     # We set the form to be our MainWindow (design) 
    app.exec_()         # and execute the app 

if __name__ == '__main__':      # if we're running file directly and not importing it 
    main()          # run the main function 

InfoMessage関数を単独で実行すると、正常に動作し、0.5秒ごとに更新されます。ただし、読み込みファイルの一部としてこれを楽しむと、GUIは空白であり、表示されます。私はそれがそこのprintステートメントのためにテスト機能にとどまっていることを知っています。

誰かが正しい方向に向かうことができますか?私はいくつかのステップを欠いていると思う。

答えて

2

まず、2つの方法があります。 1つの方法は、Python組み込みスレッドモジュールを使用することです。もう一つの方法はPyTTとはるかに統合されたQThreadライブラリを使うことです。通常、QThreadを使用してPyQtでスレッディングを行うことをお勧めします。しかし、QThreadは、PyQtとのやり取りがある場合にのみ必要です。

第2に、InfoMessageからprocessEvents()を削除しました。特定のケースで目的を果たさないためです。

最後に、スレッドをデーモンとして設定することは、スレッドが決して止まらないことを意味します。これはほとんどの機能では当てはまりません。

import sys 
import threading 
import time 

from PyQt5 import uic, QtCore, QtWidgets 
from PyQt5.QtCore import QThread 


def long_task(limit=None, callback=None): 
    """ 
    Any long running task that does not interact with the GUI. 
    For instance, external libraries, opening files etc.. 
    """ 
    for i in range(limit): 
     time.sleep(1) 
     print(i) 
    if callback is not None: 
     callback.loading_stop() 


class LongRunning(QThread): 
    """ 
    This class is not required if you're using the builtin 
    version of threading. 
    """ 
    def __init__(self, limit): 
     super().__init__() 
     self.limit = limit 

    def run(self): 
     """This overrides a default run function.""" 
     long_task(self.limit) 


class InfoMessage(QtWidgets.QDialog): 
    def __init__(self, msg='Loading ', parent=None): 
     super(InfoMessage, self).__init__(parent) 
     uic.loadUi('loading.ui', self) 

     # Initialize Values 
     self.o_msg = msg 
     self.msg = msg 
     self.val = 0 

     self.info_label.setText(msg) 
     self.show() 

     self.timer = QtCore.QTimer() 
     self.timer.setInterval(500) 
     self.timer.timeout.connect(self.update_message) 
     self.timer.start() 

    def update_message(self): 
     self.val += 1 
     self.msg += '.' 

     if self.val < 20: 
      self.info_label.setText(self.msg) 
     else: 
      self.val = 0 
      self.msg = self.o_msg 

    def loading_stop(self): 
     self.timer.stop() 
     self.info_label.setText("Done") 


class MainDialog(QtWidgets.QDialog): 
    def __init__(self, parent=None): 
     super(MainDialog, self).__init__(parent) 

     # QThread Version - Safe to use 
     self.my_thread = LongRunning(limit=10) 
     self.my_thread.start() 
     self.my_loader = InfoMessage('Loading ') 
     self.my_thread.finished.connect(self.my_loader.loading_stop) 

     # Builtin Threading - Blocking - Do not use 
     # self.my_thread = threading.Thread(
     #  target=long_task, 
     #  kwargs={'limit': 10} 
     #) 
     # self.my_thread.start() 
     # self.my_loader = InfoMessage('Loading ') 
     # self.my_thread.join() # Code blocks here 
     # self.my_loader.loading_stop() 

     # Builtin Threading - Callback - Use with caution 
     # self.my_loader = InfoMessage('Loading ') 
     # self.my_thread = threading.Thread(
     #  target=long_task, 
     #  kwargs={'limit': 10, 
     #    'callback': self.my_loader} 
     #) 
     # self.my_thread.start() 


def main(): 
    app = QtWidgets.QApplication(sys.argv) 
    dialog = MainDialog() 
    app.exec_() 

if __name__ == '__main__': 
    main() 

いずれかがこのコードに関する質問をフォローアップ尋ねること自由に感じています。

Good Luck。

編集: スレッドの完了時にコードを実行する方法を示すように更新されました。新しいパラメータがlong_taskに追加されていることに注目してください。

+0

ありがとうございました。私はそれを使って遊び始めますが、あなたはすでにそれがどのように機能するのか理解してくれたことは間違いありません。もし私がそれを理解できなければ、私は連絡を取ります。もう一度ありがとう –

+0

メッセージを表示しているスレッドをいつ停止するかを知るために、terminate/kill/closeコマンドを追加するにはどうしたらいいですか?現在のところそれが続き、制限に達すると停止しません。処理時間が変わるため、時間ベースではないようにします。私はセットアップをする必要があると思う.exit()スレッドのために私は傾けるが、これを動作させるようです。 –

+0

@MrRCタスクが完了すると、ロードダイアログの更新が自動的に停止するようにコードを更新しました。 QThreadシグナル['finished()']を使う(http://doc.qt.io/qt-4.8/qthread.html#finished)。これは、タスクがバックグラウンドで実行されているときに進行状況を更新する最善の方法です。これは、組み込みのメソッドでは通常、[GIL](https://wiki.python.org/moin/GlobalInterpreterLock)のコード実行をブロックするためです。 – daegontaven

関連する問題