Reputation: 1804
I want to write a python program run on background, and displaying PyQt5 GUI from background process on neccessary.
My solution is use RabbitMQ to do IPC work. program start with PyQt run on main thread, and start a thread listening RabbitMQ to show GUI on call.
Here is the code:
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_()
Now, everything works fine except that the label.show
line crashes the program, no widget displayed, no message printed.
The client part is listed below, sending quit
to quit the server.
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()
My question is, how and why the label.show()
shutdown the program without any error? How can I improve the program?
Or is there alternative ways to do the job?
Any suggestions are welcome.
Thank you in advance.
Upvotes: 0
Views: 1209
Reputation: 243897
The problem is that QLabel is a local variable so it will be deleted a moment after the show method is executed. The above should not cause the application to terminate but by default QApplication will be closed if at any time after showing at least one window they all close, in your case QLabel is displayed for a moment and closes, which consequently implies that the application it closes.
So the solution is to make the label a member of the class so that it is not deleted:
# ...
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()
# ...
On the other hand, Qt does not return exceptions when some function/method fails in its task, instead it informs us of the success of the execution through a variable, this does it for reasons of efficiency. And that same PyQt inherits so in 99.99% of the python code is not necessary to use try-except.
Upvotes: 2