I have a QTextEdit component created in the "main" thread of my program then I start another thread, which will be updating this QTextEdit every x seconds, but then I get this error:
QObject: Cannot create children for a parent that is in a different thread.
this is the way I'm doing it:
def initGui():
#some gui components
global txt_list
txt_list = QtGui.QTextEdit(w)
txt_list.resize(580,400)
txt_list.move(50, 50)
txt_list.setReadOnly(1)
txt_list.setFont(font_consolas)
#more gui components
def update_list():
t_monitor = threading.Thread(target=monitor_vector)
t_monitor.daemon = True
t_monitor.setName('monitor')
t_monitor.start()
def monitor_vector():
#retrieve info...
lock = threading.Lock
lock = True
txt_list.clear() #clear list, to set the new one
txt_list.setText('updated list')
lock = False
this two last lines of code give me the above mentioned error. Can someone give me a clue on how to handle this?
thanks!
One of the main gotcha's about Qt is that you cannot call any QWidget methods from any thread other than the main GUI thread. All of your communication must be done by emitting signals from the extra threads, which will forward to the main gui.
To start, I see you are using globals, and a lack of the self
keyword, so I assume you are not using classes. My example will incorporate a class example as well.
This is example is bare bones, just like yours, outlining the direction you might want to take:
from PyQt4 import QtGui, QtCore
class MyWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
...
self.txt_list = QtGui.QTextEdit(self)
self.txt_list.resize(580,400)
self.txt_list.move(50, 50)
self.txt_list.setReadOnly(1)
self.txt_list.setFont(font_consolas)
...
self.monitor = Monitor()
self.monitor.updateText.connect(self._handleTextUpdate)
self.monitor.update_list()
def _handleTextUpdate(self, txt):
self.txt_list.clear()
self.txt_list.setText(txt)
class Monitor(QtCore.QObject):
updateText = QtCore.pyqtSignal(str)
def update_list(self):
t_monitor = Thread(self.monitor_vector, parent=self)
t_monitor.daemon = True
t_monitor.setName('monitor')
t_monitor.start()
def monitor_vector(self):
...
self.updateText.emit('updated list')
class Thread(QtCore.QThread):
def __init__(self, fn, args, kwargs, parent=None):
super(Thread, self).__init__(parent)
self._fn = fn
self._args = args
self._kwargs = kwargs
def run(self):
self._fn(*self._args, **self._kwargs)
The main thing to notice is that the functions running in the thread are emitting signals. They have no knowledge of the QWidgets in the other classes. Your MyWidget
class connects the signal to a slot that can update the QLineEdit. When the thread emits a signal, it will be queued into the main thread and executed by the receiving slot.
I also created a simple QThread subclass that can take a function and args, replicating the way the standard lib Thread class works. You should stick to using QThread because it is a QObject subclass, and supports signals and can run an event loop.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.