[PyGUI] Failed when communicating between threads - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: [PyGUI] Failed when communicating between threads (/thread-4831.html) |
Failed when communicating between threads - pythonisse - Sep-11-2017 Hi everybody, I am trying to display an image on the window, but when I try it, I got this error: "QPixmap: It is not safe to use pixmaps outside the GUI thread" As you can see I am using two threads: one for the GUI and another one of the APP logic. The new image path file is generated in the app logic thread which should be sent to the GUI thread. For this reason, I decided to use the Signal & slots communication mechanism. I put the basic logic of my still-to-finish solution into small pieces to illustrate it, so you can run it and give me a hand if you have time. The program basically shows an internal value for each thread every x seconds, and every time it is changed on LOGIC class it should be changed on GUI class too - just an example of what I would like to do with the final widget that can be only changed form its own thread: import threading from PyQt4.QtCore import QObject, SIGNAL import time import random class LOGIC (threading.Thread, QObject): def __init__(self): QObject.__init__(self) threading.Thread.__init__(self) self.id = "LOG" self.value = 0 def run(self): while True: self.value = random.randint(1, 10) print ("[" + self.id + "] value = " + str(self.value)) self.on_value_changed(self.value) time.sleep(4) def on_value_changed(self, value): print ("[" + self.id + "] Running on_value_changed()") self.emit(SIGNAL('changeThisPlease(int)'), int(self.value)) class GUI (threading.Thread, QObject): def __init__(self): QObject.__init__(self) threading.Thread.__init__(self) self.id = "GUI" self.value = 0 def run(self): while True: print ("[" + self.id + "] value = " + str(self.value)) time.sleep(1) def on_GUI_changeValue(self, value): print ("[" + self.id + "] Running on_GUI_changeValue()") self.value = int(value) if __name__ == '__main__': myLogic = LOGIC() myLogic.start() myGui = GUI() myGui.start() myLogic.connect(myLogic, SIGNAL("changeThisPlease(int)"), myGui.on_GUI_changeValue)The GUI thread always shows the initial value, so it's never changed by the signal emitted by LOGIC, what am I doing wrong? Could you please give me a hand? Thanks so much for reading RE: Failed when communicating between threads - hbknjr - Sep-11-2017 I don't think signals works between two threads, they only work between main GUI and other threads. on_GUI_changeValue function is never called as thread.start() will only execute run method.To communicate between threads you can use global variables or queues. (Sep-11-2017, 11:10 AM)pythonisse Wrote: "QPixmap: It is not safe to use pixmaps outside the GUI thread" What they mean by GUI thread is the main thread that is started with .show() method.
RE: Failed when communicating between threads - pythonisse - Sep-11-2017 Thanks for taking the time to post your answer. Precisely I kept trying and finally I sorted it out by using Queue(). It works like a charm now! Just a bit frustrating I couldn't make it work with signals, but maybe it is just impossible with that approach Regards RE: Failed when communicating between threads - Alfalfa - Oct-03-2017 I think the move to thread approach is usually recommended for PyQt, such as: #!/usr/bin/python3 import sys import time from PyQt5 import QtGui, QtWidgets from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import QSystemTrayIcon class workerExample(QObject): signalExample = pyqtSignal(str, int) def __init__(self): super().__init__() @pyqtSlot() def loop(self): while True: #Do your work here... self.signalExample.emit("leet", 1337) time.sleep(5) class guiExample(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.worker = workerExample() self.workerThread = QThread() #move the Worker object to the Thread object self.workerThread.started.connect(self.worker.loop) #init worker loop() at startup self.worker.moveToThread(self.workerThread) self.worker.signalExample.connect(self.signalExample) #Connect your signals/slots self.workerThread.start() #Do your gui operations here... #... def signalExample(self, text, number): print(text) print(number) if __name__== '__main__': app = QtWidgets.QApplication(sys.argv) Dialog = guiExample() sys.exit(app.exec_()) |