2016-12-25 73 views
4

我一直在PyQt和线程信号/插槽混乱。 这里的情况是我无法找到我的错误:PyQt信号跨线程

我有一个类(MultipleProcessLauncher),它能够在不同的线程启动多个进程。 我捕获每个进程的标准输出并将这些消息发送到由另一个线程读取的单个队列(OutputWorker),这最后一个线程应该发送一个onNewMessage信号(我认为它没有)捕获主类,但是回调函数永远不会被调用。

  • 的进程线程填充队列的消息
  • 读数搭线所有这些消息(我可以在while循环与print(item)打印出来)

: - 信号的读线程似乎并没有发出任何东西,所以主线程的回调函数永远不会被调用...

您的帮助将不胜感激,我觉得我失去了跨线程信号的东西...

class OutputWorker(QObject): 
    onNewMessage = pyqtSignal(['QString']) 

    def __init__(self, queue, parent=None): 
     super(OutputWorker, self).__init__(parent) 
     self.queue = queue 

    def work(self): 
     while True: 
      item = self.queue.get() 
      self.onNewMessage.emit(item) 
      self.queue.task_done() 

class MultipleProcessLauncher(QObject): 
    commandEvent = pyqtSignal(['QString']) 

    def __init__(self, parent=None): 
     super(MultipleProcessLauncher, self).__init__(parent) 

     self.messaging_queue = Queue() 

     # Start reading message 
     self.reading_thread = QThread() 

     self.worker = OutputWorker(self.messaging_queue) 
     self.worker.moveToThread(self.reading_thread) 
     self.worker.onNewMessage.connect(self.command_event) 

     self.reading_thread.started.connect(self.worker.work) 
     self.reading_thread.start() 

    def execute(self, command): 
     p = subprocess.Popen(command, stdout=subprocess.PIPE) 
     t = Thread(target=self.enqueue, args=(p.stdout, self.messaging_queue)) 
     t.daemon = True 
     t.start() 

    def enqueue(self, stdout, queue): 
     for line in iter(stdout.readline, b''): 
      queue.put(line.decode()) 
     stdout.close() 

    def command_event(self, event): 
     # This point is never reached 
     print('message received') 

if __name__ == '__main__': 
    manager = MultipleProcessLauncher() 
    manager.execute('ipconfig') 

    time.sleep(100) 
+0

我不认为'item'会成为'QString'。您可能想要将您的信号定义更新为'pyqtSignal(str)'或类似的。不知道这是否是问题的原因。 –

+0

如果我用str更改QString,或者即使我没有在我的信号和插槽上放置任何参数,也不起作用 – And0rian

回答

3

Qt的跨线程的信号是基于事件循环,所以你需要Exec中的QApplication以便有一个主事件循环处理信号来自其他线程。例如:

if __name__ == '__main__': 
    app = QApplication([]) 
    manager = MultipleProcessLauncher() 
    manager.execute('ipconfig') 
    MAX_WAIT_MSEC = 100 * 1000 # 100 seconds 
    QTimer.singleShot(MAX_WAIT_MSEC, app.quit) 
    app.exec() 

在您的实际应用根据用户的输入,因此执行将是一个插槽,不会有必要退出,等你可能会执行经理,但你的理念。

+0

你说得对! – And0rian