2

When I try to use one QDialog object from threads I get this error. Here is the code I'm using:

import threading
import test_qdialog
from PyQt4 import QtGui, QtCore


class MyThread(threading.Thread):
    def __init__(self, id, window, mutex):
        self.id = id
        self.window = window
        self.mutex = mutex
        super(MyThread, self).__init__()

    def run(self):
        with self.mutex:
            result = self.window.exec_()
            if result == QtGui.QDialog.Accepted:
                print "Thread %d: %s" % (self.id, self.window.message_input.text())


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)

    mutex = threading.Lock()
    threads = []
    window = test_qdialog.MyDialog()

    for i in range(5):
        thread = MyThread(i, window, mutex)
        thread.start()
        threads.append(thread)

    for thread in threads:
        thread.join()

    sys.exit(app.exec_())

As written in this answer, if I get it right, I can't do it this way. But how can I do it then?

Community
  • 1
  • 1
Dmitrii Mikhailov
  • 5,053
  • 7
  • 43
  • 69
  • 2
    Actually Qt widgets aren't thread safe. – fasked Feb 02 '14 at 09:08
  • @fasked, and there is no workaround? – Dmitrii Mikhailov Feb 02 '14 at 09:52
  • There is no legal workaround. Qt documentation explicitly says that widgets can be accessed from main thread only. – fasked Feb 02 '14 at 10:00
  • 2
    @DmitryMikhaylov If it is any help, I've created a nice utility which allows you to run arbitrary methods in the main thread of a Qt application. So from a thread, you could call `inmain(widget.setText,my_text)` for example and it would then post an event to the MainThread and run your specified method. If you are interested, check out https://bitbucket.org/philipstarkey/qtutils. Written for PySide, but should be trivial for you to port to PyQt! – three_pineapples Feb 02 '14 at 11:20
  • @three_pineapples invoke_in_main is very cool.) i created a decorator with it, which magically makes a slot run in another thread and the thread can communicate with GUI transparently. – Winand Apr 15 '15 at 10:49

2 Answers2

2

You can only create and use GUI widgets on main thread (every UI library that I know is like that). However, you can easily pass signals from threads to main using QtCore.QtThread. See for example the answer to PyQt threads and signals - how to properly retrieve values (even if the answer is not what the OP was looking for, it is relevant to your situation). May also find this SO post useful.

So instead of creating or accessing the dialog from thread, you would emit a signal from thread, and have your main window connected to it create the dialog when it receives the signal. Qt takes care of transfering data between threads. Will work like a charm.

Definitely take a close look at Qt Threading Basics, if you haven't already (if you have, may want to post questions about parts you don't understand, there is tons of important info there).

Community
  • 1
  • 1
Oliver
  • 27,510
  • 9
  • 72
  • 103
0

The QT Widgets can't be accessed from a thread which is not the main thread. For example, if you call mainwindow.show(), the program will crash. However, this can be easily addressed using QThread. The principle is that instead of controlling the e.g., mainwindow directly, we can send a signal to the main thread, letting the main thread to call the show() method. A signal can carry anything, such as a String or Integer. I'd strongly suggest you to watch this video. It will solve your problem in 10 minutes.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 26 '22 at 10:49