2

so I have a QTextEdit within a Main Window in my GUI. I want to live update the text in this by pulling from a remotely updating list. I don't know how to infinitely check this list, without either a) doing an infinite loop or b) thread.

a) Crashes the GUI, as it is an infinite loop b) produces an error saying:

QObject: Cannot create children for a parent that is in a different thread.

Which I understand.

What could I do to fix this?

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
sudobangbang
  • 1,406
  • 10
  • 32
  • 55
  • Why not using Signals and Slots for dynamic updates of the GUI? – NoDataDumpNoContribution Jun 24 '14 at 09:06
  • 1
    possible duplicate of [Introduce a text in a lineEdit of PyQt from a thread](http://stackoverflow.com/questions/24266251/introduce-a-text-in-a-lineedit-of-pyqt-from-a-thread) – three_pineapples Jun 24 '14 at 10:15
  • Also see http://stackoverflow.com/questions/21071448/redirecting-stdout-and-stderr-to-a-pyqt4-qtextedit-from-a-secondary-thread (not a duplicate of this one, but is highly relevant) – three_pineapples Jun 24 '14 at 10:16
  • @three_pineapples. While I appreciate your comments, I don't believe either of these are appropriate. In the first link you posted the OP, like myself, is using python threads not Qthreads as you noted. The second link, to your answer, also involve Qthreads. Also, neither of these have mentioned dynamic updates (live updating during runtime). Perhaps you could clarify your possible solution to my problem instead of providing links with an unclear direction. – sudobangbang Jun 24 '14 at 12:08
  • @three_pineapples, again my knowledge is fairly limited with PyQt, do you think my best bet would be to go with Qthreads? – sudobangbang Jun 24 '14 at 12:41
  • I would strongly suggest using threads given you need to pull from a remotely updating list. Without seeing more details, it is difficult to give specific implementation details, but generally you use a thread to get the data (because getting the data is a long/blocking operation) and then you send it to the GUI thread. The first question I linked you to has an answer by me that shows how to communicate from a python thread to the GUI thread (using my qtutils library). The second link shows how to communicate from a QThread to the GUI thread. – three_pineapples Jun 25 '14 at 08:59
  • I would suggest picking the type of thread you want to use (Python or QThread) and asking a new question where you spell out the more specific details on what you want/have done (eg how/where you are getting your data from) – three_pineapples Jun 25 '14 at 09:01
  • So I followed your suggestion, using Qthreads, the error was actually generated only by calling the QtextEdit.setText() within the loop. When just appending this worked fine for dynamic updates. However, I need to clear it somehow. Thanks @three_pineapples – sudobangbang Jun 25 '14 at 11:21
  • 1
    Yes, but you should not call any QTextEdit methods from the thread, it risks crashing the program. So you need to make and send another signal for clearing it. – three_pineapples Jun 25 '14 at 21:58

2 Answers2

12

this is how it works without threads :)

1) Create pyqt textEditor logView:

self.logView = QtGui.QTextEdit()

2)add pyqt texteditor to layout:

layout = QtGui.QGridLayout()
layout.addWidget(self.logView,-ROW NUMBER-,-COLUMN NUMBER-)
self.setLayout(layout)

3) the magic function is:

def refresh_text_box(self,MYSTRING): 
    self.logView.append('started appending %s' % MYSTRING) #append string
    QtGui.QApplication.processEvents() #update gui for pyqt

call above function in your loop or pass concatenated resultant string directly to above function like this:

self.setLayout(layout)
self.setGeometry(400, 100, 100, 400)
QtGui.QApplication.processEvents()#update gui so that pyqt app loop completes and displays frame to user
while(True):
    refresh_text_box(MYSTRING)#MY_FUNCTION_CALL
    MY_LOGIC
#then your gui loop
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
dialog = MAIN_FUNCTION()
sys.exit(dialog.exec_())
hemraj
  • 964
  • 6
  • 14
2

Go for QThread, after all, moving your code from a python thread to QThread shouldn't be hard. Using signals & slots is imho the only clean solution for this. That's how Qt works and things are easier if you adapt to that. A simple example:

import sip
sip.setapi('QString', 2)

from PyQt4 import QtGui, QtCore

class UpdateThread(QtCore.QThread):

    received = QtCore.pyqtSignal([str], [unicode])

    def run(self):
        while True:
            self.sleep(1) # this would be replaced by real code, producing the new text...
            self.received.emit('Hiho')

if __name__ == '__main__':

    app = QtGui.QApplication([])

    main = QtGui.QMainWindow()
    text = QtGui.QTextEdit()
    main.setCentralWidget(text)

    # create the updating thread and connect
    # it's received signal to append
    # every received chunk of data/text will be appended to the text
    t = UpdateThread()
    t.received.connect(text.append)
    t.start()

    main.show()
    app.exec_()
sebastian
  • 9,526
  • 26
  • 54