2016-10-21 8 views
0

Я столкнулся с этой проблемой QCoreApplication, где вызов ввода() после завершения QObject, выполняемого внутри QThread, вызывает бесконечную печать цикла в консоли «QCoreApplication :: exec: цикл событий уже запущен».Почему input() вызывает «QCoreApplication :: exec: цикл событий уже запущен»?

В коде я создаю родового работника как объект QObject, переместите его в QThread (санкционированный способ использования QThread, а не подклассифицировать его), а затем выполните другую функцию QObject (Мастер-класс) внутри родового рабочего. Все работает нормально, пока я не вызываю 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(), управление вернется к циклу событий, а затем дождитесь дальнейшего взаимодействия с пользователем, что является нормальным и ожидаемым поведением.

Вы не даете понять, что вы ожидаете после этого. Но если вы хотите, чтобы программа бросить курить, просто сделать это:

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

предупреждающее сообщение Qt безвреден, но он может быть удален, как это:

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

    app = QCoreApplication(sys.argv) 
    ... 

Единственная реальная проблема в вашем примере реализация потоковой передачи. Если вы добавите строку print(QThread.currentThread()) в Worker.run(), Master.do() и main(), вы увидите, что все три выполнены в основной строке . Это связано с тем, что вы подключили сигнал thread.startдо, перемещая работника в другую ветку. Лучший (то есть самый легко ремонтируемый) способ исправить эту проблему, чтобы всегда использовать декоратор @pyqtSlot на любых слотах, которые подключены по потокам, потому что тогда не будет иметь значения, когда производятся сигнальные соединения. (См. this answer для более полного объяснения этой проблемы).

+0

Отлично! Я решил 2 вопроса с вашим ответом. Большое спасибо. – R01k

 Смежные вопросы

  • Нет связанных вопросов^_^