从后台进程显示 PyQt5 小部件



我想编写一个在后台运行的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()如何以及为什么关闭程序而没有任何错误?如何改进该计划?

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

欢迎任何建议。

提前谢谢你。

问题是 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。

最新更新