我想编写一个在后台运行的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。