从后台进程显示PyQt5小部件

时间:2019-05-31 10:06:55

标签: python pyqt rabbitmq pyqt5 pika

我想编写一个在后台运行的python程序,并在必要时从后台进程显示PyQt5 GUI。

我的解决方案是使用RabbitMQ进行IPC工作。程序以在主线程上运行的PyQt开始,然后启动一个侦听RabbitMQ的线程以在调用时显示GUI。

代码如下:

from PyQt5.QtWidgets import QApplication, QLabel
from PyQt5.QtCore import QThreadPool, QObject, QRunnable, pyqtSignal
import traceback
import pika
import sys

class RabbitMQSignals(QObject):
    target = pyqtSignal(int)

class MessageListener(QRunnable):

    def __init__(self):
        super(MessageListener, self).__init__()

        self.signals = RabbitMQSignals()

    def run(self):
        self.connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
        self.channel = self.connection.channel()
        self.channel.queue_declare(queue='ui')
        self.channel.basic_consume(queue='ui', on_message_callback=self.dispatch, auto_ack=True)
        print('Waiting for signals')
        self.channel.start_consuming()

    def dispatch(self, channel, method, properties, body):
        body = body.decode('utf-8')
        if body == 'quit':
            sys.exit(0)

        print('[x] Received %s' % body)
        self.signals.target.emit(0)


class MainWidget(QObject):

    def __init__(self):
        super(MainWidget, self).__init__()

    def show(self, action):
        try:
            print('[x] Dispatched :' + str(action))
            label = QLabel('Hello World')
            label.show()
        except:
            print(traceback.format_exc())


if __name__ == '__main__':
    app = QApplication([])

    widget = MainWidget()
    pool = QThreadPool()
    listener = MessageListener()
    listener.signals.target.connect(widget.show)
    pool.start(listener)

    app.exec_()

现在,一切正常,除了label.show行使程序崩溃,不显示小部件,不打印消息。

下面列出了客户端部分,它发送quit退出服务器。

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='ui')
channel.basic_publish(exchange='', routing_key='ui', body='show label')
connection.close()

我的问题是,label.show()如何以及为什么关闭程序而没有任何错误?我该如何改善程序?

还是有其他方法可以完成这项工作?

欢迎提出任何建议。

谢谢。

1 个答案:

答案 0 :(得分:1)

问题在于QLabel是局部变量,因此将在执行show方法之后将其删除。以上内容不会导致应用程序终止,但是默认情况下,如果至少在显示至少一个窗口之后它们都关闭,则QApplication将关闭,在这种情况下,QLabel会暂时显示并关闭,这意味着它关闭了该应用程序

因此解决方案是使标签成为类的成员,以便不将其删除:

# ...
class MainWidget(QObject):
    def __init__(self):
        super(MainWidget, self).__init__()
        self.label = QLabel("Hello World")

    def show(self, action):
        print('[x] Dispatched :' + str(action))
        self.label.show()
# ...

另一方面,当某个函数/方法在其任务中失败时,Qt不会返回异常,而是通过变量通知我们执行成功,这是出于效率的考虑。而且PyQt继承了相同的内容,因此在99.99%的python代码中,无需使用try-except。