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.
Related
I've made routine with Python's threading module to run a subprocess and wait for it to finish.
I do the threading with the following line :
t1=Thread(target=self.routineFunction, args=(self, "file1.txt", "file2.txt", self.nextFunction)).start()
Inside my function routineFunction(self,file1,file2,nextFunction) I call the next function to run once the subprocess has finished running.
Everything works fine until then.
But if I create new QObject items in my next function, I receive a lot of errors :
- "QPixmap: It is not safe to use pixmaps outside the GUI thread"
- "QObject::startTimer: QTimer can only be used with threads started with QThread"
My guess is that when I call nextFunction from the routine it is ran in the same thread as the routine, hence the errors.
Is there a way to call a function from the routine inside the "main" or "normal" thread ?.
Thank you for your help.
Generally, it is okay to call functions from other threads. But many GUI libraries (QT is among them) have some restrictions on this behavior.
For example, there are designated thread called 'GUI thread' which handles all graphical stuff, like dispatching messages from OS, redrawing windows, etc. And you also restricted to work with GUI withing this only thread. So, for example, you should not create QPixmap in other threads.
QTimer uses some QThread's internal data, so you should use such timers in threads only started with QThread, but not with plain Python thread module.
Returning to your question, if you want ot work with QT, you should spawn your threads using QThread and post events to GUI thread using postEvent() method. This will guarantee consistence of QT internal data structures.
So, you can ran your code in any QT thread, but if you want to work with GUI (your QObject uses QPixmap, so it is the case), you need to handle such calls only in GUI thread.
Ok so I think that werewindle solution is possible. Unfortunatly, I found it difficult to convert my current script from Thread to QThread (I am new to threading in general).
I found a workaround :
Instead of passing nextFunction as an argument, I pass a queue = Queue.Queue() and I use queue.put(True) if my subprocess in my new thread is a success. There is no more nextFunction, I simply wait for a value in the queue with queue.get().
By doing this, I can then continue in the GUI thread.
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.
I'm writing a multi-threaded application that utilizes QThreads. I know that, in order to start a thread, I need to override the run() method and call that method using the thread.start() somewhere (in my case in my GUI thread).
I was wondering, however, is it required to call the .wait() method anywhere and also am I supposed to call the .quit() once the thread finishes, or is this done automatically?
I am using PySide.
Thanks
Both answers depend on what your code is doing and what you expect from the thread.
If your logic which uses the thread needs to wait synchronously for the moment QThread finishes, then yes, you need to call wait(). However such requirement is a sign of sloppy threading model, except very specific situations like application startup and shutdown. Usage of QThread::wait() suggests creeping sequential operation, which means that you are effectively not using threads concurrently.
quit() exits QThread-internal event loop, which is not mandatory to use. A long-running thread (as opposed to one-task worker) must have an event loop of some sort - this is a generic statement, not specific to QThread. You either do it yourself (in form of some while(keepRunning) { } cycle) or use Qt-provided event loop, which you fire off by calling exec() in your run() method. The former implementation is finishable by you, because you did provide the keepRunning condition. The Qt-provided implementation is hidden from you and here goes the quit() call - which internally does nothing more than setting some sort of similar flag inside Qt.
I have a program that receives serial data and uses matplotlib to graph it using Tkinter. I have this working currently, but I've had to use the .after() function to poll a queue for data. In other UI frameworks I've used in the past (different projects in C) there has been a way to ask the UI framework to call a function given to it from the mainloop (either after some amount of time, during idle, etc). If I try to use .after() on a thread which isn't the mainloop, it doesn't work and complains at me.
Is there a way to call a user supplied function, provided on a thread which isn't the mainloop, from the mainloop? Or, is there a way to instruct the mainloop to wake up and do some work if a Queue gets some data?
Thanks.
I've heard that you can call event_generate from the non-GUI thread. If you do call event_generate, I've read that you should give the value of tail to the when parameter.
I've personally only done this in one project, but it seemed to work fine.
I have a PyQt4 application, which at some point packs a big file using the tarfile module. Since the tarfile module does not implement any callback strategy, it blocks and the Qt GUI gets unresponsive.
I want the GUI to keep updating during that time. The only possibility is a separate thread.
So, I start a QThread. What do I have to do in the QThread to make the GUI update itself?
As soon, as the tar process is finished, I want the thread to finish.
Thanks!
Nathan
QThread's are pretty much identical to normal Python threads so you can just use normal communication methods. However, QThreads also have a few signals available, so if you simply connect to those, than you're done.
In your GUI code do something like this and you're pretty much done:
thread = Thread()
thread.finished.connect(gui.do_update_thingy)
There is also a terminated and started signal available which you can use :)