3

I have the following code but it's complaining that I cannot access the UI data from my thread. In my example code below, What is the best way I can access the userInputString value so my threading can run?

self.nameField is a PyQt QLineEdit.

QObject::setParent: Cannot set parent, new parent is in a different thread
QPixmap: It is not safe to use pixmaps outside the GUI thread
QWidget::repaint: Recursive repaint detected

import myUI

class MainUIClass(QtGui.QMainWindow, myUI.Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainUIClass, self).__init__(parent)
        self.setupUi(self)

        self.startbutton.clicked.connect(self.do_work)

        self.workerThread = WorkerThread()
        self.connect(self.workerThread, SIGNAL("myThreading()"), self.myThreading, Qt.DirectConnection)

    def do_work(self):
        self.userInputString = self.nameField.Text()
        self.workerThread.start()

    def myThreading(self):

        if userInputString is not None:
            #Do something

class WorkerThread(QThread):
    def __init__(self, parent=None):
        super(WorkerThread, self).__init__(parent)

    def run(self):
        self.emit(SIGNAL("myThreading()"))

if __name__ == '__main__':
    a = QtGui.QApplication(sys.argv)
    app = MainUIClass()
    app.show()
    a.exec_()
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
joke4me
  • 812
  • 1
  • 10
  • 29
  • 1
    You should read " How to use QThread the right way" http://stackoverflow.com/questions/16879971/example-of-the-right-way-to-use-qthread-in-pyqt http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-2/ You're also using old style signal ... For you problem, you should use Signals and slot...you run your process in a thread then from this thread send a signals to the GUI thread which can access the GUI elements – PyNico Feb 13 '17 at 09:51
  • Thanks for pointing that out. All i'm trying to do is to be able to access the "userInputString" value from within my thread class but don't know how to pass that value from the MainUI class to the thread class. Do you think a shared multithreading Array or Value data type would be another way to do it? – joke4me Feb 13 '17 at 17:46
  • @joke4me. The code in your question does not produce those error messages. In fact, with minor corrections, it works exactly as expected. Please read the guidance on how to provide a [mcve]. – ekhumoro Feb 13 '17 at 18:13

1 Answers1

5

Not sure if it's what you need but here is a working QThread exemple using Qt5

import time
import sys
from PyQt5 import QtWidgets, QtGui, QtCore

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.worker_thread = WorkerThread()
        self.worker_thread.job_done.connect(self.on_job_done)
        self.create_ui()

    def create_ui(self):
        self.button = QtWidgets.QPushButton('Test', self)
        self.button.clicked.connect(self.start_thread)
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.button)

    def start_thread(self):
        self.worker_thread.gui_text = self.button.text()
        self.worker_thread.start()

    def on_job_done(self, generated_str):
        print("Generated string : ", generated_str)
        self.button.setText(generated_str)


class WorkerThread(QtCore.QThread):

    job_done = QtCore.pyqtSignal('QString')

    def __init__(self, parent=None):
        super(WorkerThread, self).__init__(parent)
        self.gui_text = None

    def do_work(self):

        for i in range(0, 1000):
            print(self.gui_text)
            self.job_done.emit(self.gui_text + str(i))
            time.sleep(0.5)

    def run(self):
        self.do_work()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    test = MainWindow()
    test.show()
    app.exec_()
PyNico
  • 695
  • 5
  • 21
  • Thanks, like you said the code snippet works fine. The reason of the crash was because I was popping an alert from the thread inside if the try/except block. Thread doesn't seems to like any UI stuff inside the thread. When I instead print to console, everything is working fine, So I need to figure out how to pass that info back to the UI class to be displayed to the user – joke4me Feb 17 '17 at 12:33
  • @joke4me you can just emit the object back in WorkerThread, job_done can return an object as QtCore.pyqtSignal(object). – misantroop Feb 19 '20 at 06:25
  • @joke4me did you found a solution? – adri567 Apr 03 '21 at 10:11