从后台进程显示 PyQt5 小部件
Display PyQt5 widget from background process
我想在后台编写一个 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方法后片刻被删除。以上不应导致应用程序终止,但默认情况下,如果在显示至少一个 window 后的任何时候它们都关闭,则默认情况下 QApplication 将关闭,在您的情况下 QLabel 显示片刻并关闭,因此这意味着它关闭的应用程序。
所以解决方案是让标签成为class的成员,这样它就不会被删除:
# ...
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()
# ...
另一方面,当一些function/method任务失败时,Qt不会return异常,而是通过变量通知我们执行成功,这样做是有原因的的效率。同样的 PyQt 继承了 99.99% 的 python 代码没有必要使用 try-except.
我想在后台编写一个 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方法后片刻被删除。以上不应导致应用程序终止,但默认情况下,如果在显示至少一个 window 后的任何时候它们都关闭,则默认情况下 QApplication 将关闭,在您的情况下 QLabel 显示片刻并关闭,因此这意味着它关闭的应用程序。
所以解决方案是让标签成为class的成员,这样它就不会被删除:
# ...
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()
# ...
另一方面,当一些function/method任务失败时,Qt不会return异常,而是通过变量通知我们执行成功,这样做是有原因的的效率。同样的 PyQt 继承了 99.99% 的 python 代码没有必要使用 try-except.