我想编写一个在后台运行的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()
如何以及为什么关闭程序而没有任何错误?我该如何改善程序?
还是有其他方法可以完成这项工作?
欢迎提出任何建议。
谢谢。
答案 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。