简体   繁体   中英

how to clear QTextEdit in different thread in pyQt4

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM