2016-10-21 7 views
0

QObjectのはQThread内で実行すると、コンソール「QCoreApplication ::幹部:イベントループがすでに実行されている」と無限ループの印刷が発生し終了した後、私は入力を呼び出す()このQCoreApplicationの問題に遭遇してきました。なぜinput()が "QCoreApplication :: exec:イベントループが既に実行されていますか"を引き起こしますか?

QObjectとしてジェネリックワーカーを作成し、QThread(サブクラス化する代わりにQThreadを使用する認可された方法)に移動し、汎用ワーカー内で別のQObject(Masterクラス)関数を実行します。マスターが実行された後にinput()を呼び出さない限り、すべて正常に動作します。この問題は、(マスタインスタンスの関数ではなく)ワーカーで直接関数を実行する場合にも発生することに注意してください。ここで

は、問題を再現するサンプルコードです:

import sys 
from PyQt4.QtCore import QCoreApplication, QObject, QThread, pyqtSignal, pyqtSlot 


class Worker(QObject): 
    """ 
    Generic worker. 
    """ 
    start = pyqtSignal(str) 
    finished = pyqtSignal() 

    def __init__(self, function): 
     QObject.__init__(self) 
     self._function = function 
     self.start.connect(self.run) 

    def run(self): 
     self._function() 
     self.finished.emit() 


class Master(QObject): 
    """ 
    An object that will use the worker class. 
    """ 
    finished = pyqtSignal() 

    def __init__(self): 
     QObject.__init__(self) 

    @pyqtSlot() 
    def do(self): 
     print("Do what?") 
     self.finished.emit() 


def done(): 
    # FIXME This will cause an infinite loop printing to the console: 
    # "QCoreApplication::exec: The event loop is already running" 
    input("Enter your answer: ") 


def main(): 
    app = QCoreApplication(sys.argv) 

    master = Master() 
    worker = Worker(master.do) 
    master.finished.connect(done) 

    thread = QThread() 
    thread.started.connect(worker.run) 
    worker.moveToThread(thread) 

    # Terminating thread gracefully, or so. 
    worker.finished.connect(thread.quit) 
    worker.finished.connect(worker.deleteLater) 
    thread.finished.connect(thread.deleteLater) 

    thread.start() 

    sys.exit(app.exec_()) 


if __name__ == "__main__": 
    main() 

答えて

2

あなたの例ではinputとは本当の問題はありません。 done()でenterキーを押すと、コントロールはイベントループに戻り、さらにユーザーの操作を待ちます。これは通常の動作であり、予想される動作です。

あなたはそれ以降に起こると予想されることを明確にしません。あなたがプログラムを終了したい場合はしかし、ちょうどこの操作を行います。

def done(): 
    input("Enter your answer: ") 
    QCoreApplication.quit() 

をQtの警告メッセージは無害ですが、次のように取り外すことができます:あなたの例では唯一の本当の問題がある

def main(): 
    from PyQt4.QtCore import pyqtRemoveInputHook 
    pyqtRemoveInputHook() 

    app = QCoreApplication(sys.argv) 
    ... 

スレッド実装。あなたがWorker.run()Master.do()main()に行print(QThread.currentThread())を追加する場合は、すべての3つがメインスレッドで実行されていることがわかります。これは、thread.start信号を接続してからのワーカーを別のスレッドに移動するためです。スレッド間で接続されているスロットに常に@pyqtSlotデコレータを使用するように、この問題を解決する最も簡単な方法(つまり、最も簡単にメンテナンス可能)は、シグナル接続がいつ行われるかは関係ありません。 (この問題の詳細については、this answerを参照してください)。

+0

優秀!私はあなたの答えに2つの問題を解決しました。どうもありがとう。 – R01k

関連する問題