RforMaser RforMaser - 1 month ago 11
Python Question

how can i real time update the text without affecting other event(pyqt)

in my program, i would like to continually set text into text browser, but it seem to have delay when i click another button. There is my code:

class Ui_MainWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.setupUi(self)
self.th0 = TestThread()
self.pushButton.clicked.connect(self.runthread)

def runthread(self):
self.th0.start()
self.chilWid.Consumer()
QtGui.qApp.processEvents()

def setupUi(self, Widget):
self.gridLayout = QtGui.QGridLayout()
self.pushButton = QtGui.QPushButton()
self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1)
self.chilWid = ChildWid()
self.gridLayout.addWidget(self.chilWid, 1, 0, 1, 1)

self.setLayout(self.gridLayout)

manager = Manager()
manager2 = Manager()
q = manager.Queue()
q2 =manager2.Queue()
l = manager.Lock()
l2 =manager2.Lock()


this class is a thread that will control the producer

class TestThread(QThread):
def __init__(self):
QThread.__init__(self)
self.t = ChildWid()
def run(self):
while (not self.stopped):
ps0 = Process(target=Producer, args=(q, l, 'eth0', q2, l2))
#### Producer is another program that will generate
text continually and save into q
ps0.start()


this class only contain a text browser and will be inserted by class MainWindow. it also collects the data from queue and display it on text browser

class ChildWid(QWidget):
def __init__(self):
QWidget.__init__(self)
self.text = QTextEdit()
self.lay = QHBoxLayout(self)
self.lay.addWidget(self.text)

def Consumer(self):
global q, q2, q3,l,l2,l3
while True:
try:
task = q.get(block=False)
QtGui.qApp.processEvents()
self.text.setText(str(task))
except:
pass


when i click
pushButton
, text browser will display the text generate by
Producer
normally. But another button like
pushbutton
or whole user interface response are very slow. dose any suggestion for me? thanks

**********new updated

class TestThread(QThread,QObject):
testsinal = pyqtSignal(str)

def __init__(self):
. . .
self.t = ChildWid()

def TestSignal(self):
self.testsinal.emit('some text message')
self.testsinal.connect(self.handle)
@QtCore.pyqtSlot(str)
def handle(self,str):
print str
self.t.text.setText(str)

def run(self):
print"Thread run normally"
while (self.stopped):
ps0 = Process(target=L2PS_v1a4.main, args=(q, l, 'eth0', q2, l2, q3))
ps0.start()

self.TestSignal()

Answer

That Consumer method with the blocking while loop looks really nasty. It's trying to act like some kind of fake event-loop, but there's no way that it can operate as efficiently as the real thing. Get rid of it.

The correct way to do this is to define a custom signal on the TestThread class, and then use it to emit the text messages from within the run() method. Cross-thread signals are thread-safe, and are posted to the receiving thread's event-queue. This means they are processed asynchronously, and so won't block the GUI:

class TestThread(QThread):
    testSignal = QtCore.pyqtSignal(str)
    ...

    def run(self):
        while (not self.stopped):
            ps0 = Process(target=Producer, args=(q, l, 'eth0', q2, l2))        
            ps0.start()
            self.testSignal.emit('some text message')


class ChildWid(QWidget):
    ...

    QtCore.pyqtSlot(str)
    def handleTestSignal(self, message):
        print(message)
        self.text.setText(message)


class Ui_MainWindow(QWidget):
    def __init__(self):
        ...
        self.th0.testSignal.connect(self.chilWid.handleTestSignal)