I have an application in which a thread (not main thread) needs access to the GUI's elements (send a click action, show a message box, etc). I am working in python and Qt and also know that it is not possible when in not main thread.
Is there a way to do it? I mean to send the action that I want to do in the thread to the main thread.
Here is a good tutorial on how to use Qthread: http://joplaete.wordpress.com/2010/07/21/threading-with-pyqt4/ . This will show how to call the GUI elements in different and custom threads. Hope this helps.
Related
I've seen this question asked in reverse a bunch of times - how to update the GUI from a subclassed QThread - but I actually want to do it in reverse. I have an application which displays the feed from a camera continuously and indefinitely, and the camera runs in a separate thread. I have the camera feed displayed in the GUI using signals from the QThread. The camera controls are in the main GUI window, and I want to be able to send those updates to an already-running camera thread. What would be the best way to do that? Thanks.
If you're using the default QThread::run() implementation which runs an event loop, then you can create a slot on the class and invoke it as a QueuedConnection (which should occur automatically).
Otherwise, you'll need to use standard thread synchronisation primitives, such as QMutex to safely access the same data from both threads.
I want to know if there is an option to know when a task is added/appended to Queue in python.
I have an application where some process runs in thread. depending on the condition a function is called from that thread. the called function will display a window.
currently its working and the window is getting displayed, my main issue is the application gets hanged when the window is displayed. I think this is due to the call of the function which displays the window was with in the thread.
So from my search some one suggested me to use Queue in python.
But when i go through python example shows that a infinite loop will be running in main thread.
If thats the case then my entire app will be in infinite loop.
You didn't specify the exact GUI framework you're using.
If you're using wxPython you can use wx.CallAfter to call a function from another thread:
def ShowWindow(txt):
wx.MessageBox(txt)
From another thread:
wx.CallAfter(ShowWindow,'message from another dimension')
This won't cause your main loop to hang.
It's said that you should not call GUI functions from a thread, but I'm wondering if this is applicable only when you call functions which affects GUI directly or it's applicable on every function provided by GUI library. By example, it is safe to call:
gobject.idle_add(self.gui.get_object('button1').set_sensitive, False)
in a thread? Because self.gui.get_object is a function from the GUI framework but self.gui.get_object('button1') is actually calling it.
Thank you for your answers.
The call you showed there seems safe. As already posted, you can read (get_object) just fine in any thread, but should only modify (set_sensitive) in the main thread. Exactly this is done here, idle_add adds the event to the main loop which is running in the main thread.
Threading with GUI is bit tricky.If you want to do it right, you should not update GUI from within any other thread than main thread (common limitation in GUI libs). However you can make multiple read calls from several threads.
I am writing a Tkinter program that requires a loop. I can't run the loop from the same class that Tkinter is in, I'm fairly certain of that much. To run said loop, I believe that I have to use a separate thread, therefore a separate class, to keep Tkinter from freezing. I have gotten Tkinter to run while a loop in the thread prints numbers. However, I need to have it configure a Tkinter window that resides in another class. How would I go about this?
You don't necessarily need another thread, because you don't necessarily need to create a loop (see my answer to your other question about using a nested loop).
However, to answer your specific question, you have to implement a queue. The worker thread will place messages of some sort on the queue, and the main thread polls the queue via the event loop and responds to the message. This is necessary because a worker thread can't directly modify tk widgets.
For an example of using threads and queues with Tkinter, see Tkinter and Threads on effbot.orb. Pay close attention to how it uses after to poll the queue every 100 ms.
Im currently trying to learn Networking with Python asyncore and pyqt4.
I coded a small server, which basically listens on some port, and resends all messages it recieves to the sender.
Since both qts QApplication.exec_() and asyncore.loop() are functions which never return i could not start them both in one thread, so i stared asyncore.loop() in a seperate daemon thread.
Whenever my server class (derived from asyncore.dispatcher) establishes or drops a connection, or sends/recieves a message, it calls methods of my window class (derived from QtGui.QMainWindow), which displays the information in a QPlainTextEdit.
But the text is not visible, unless you mark the text with the mouse.
Python console displays following error msg:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
I read on some forum, that this may be caused by calling qt-functions from another Thread, and that using signals & slots instead of plain function calling may fix the issue, but i have tried signals aswell, and i still get this error.
So, (if that is really the cause of my problems) whats the correct way to call methods of an qt object from another thread ?
EDIT More Info:
the asyncore.loop() call is located in the child thread, well its not really blocking, but only during the runtime of asyncore.loop() my Server class (asyncore.dispatcher) can do networking.
So, during the runtime of asyncore.loop() the methods of my Server class ARE called by asyncore.loop() (=child thread), and in these i
tried to emit signals to the window class running in the main thread
EDIT: Seems like i got it working now, i had some errors in my code, everything works as intended with signals now.
EDIT: small example: http://paste2.org/p/635612 (dead link)
It appears you're trying to access QtGui classes from a thread other than the main thread. Like in some other GUI toolkits (e.g. Java Swing), that's not allowed. From the Threads and QObjects web page:
Although QObject is reentrant, the GUI
classes, notably QWidget and all its
subclasses, are not reentrant. They
can only be used from the main thread.
A solution is to use signals and slots for communication between the main thread (where the GUI objects live) and your secondary thread(s). Basically, you emit signals in one thread that get delivered to the QObjects via the other thread. The page I linked to above has a good discussion of this. Actually, the whole section on Thread Support in Qt is a good read.
One potential issue you could run into is that, normally, to get full signals and slots support working across threads, you need to start an event loop in the child thread using QThread::exec() (or the PyQt equivalent) so that signals can be delivered to slots in the QObjects that live there. In your case, it sounds like you're making a blocking call to asyncore.loop(), which will prevent you from doing this. But, if you only need to emit signals in one direction (from the child thread to widgets in the main thread), I don't think you'll have a problem.