From my wxpython GUI app I have an rsync task that I kick off as a multiprocessing.Process.
The idea is to update a wx.textCtrl with the constant output from this background process.
I am using a pubsub subscribe method.
The functions work fine but I can't get the textCtrl to update.
If I use a CallAfter method I get this crash/error:
The process has forked and you cannot use this CoreFoundation
functionality safely. You MUST exec(). Break on
THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC()
to debug.
If I don't use that method and I try to append the text directly to the textctrl nothing happens.
Any ideas?
Thanks!
Adam
The problem is that the child process can't write back to the main process. Use a queue to pass messages back to the main process, and update the control from within a timer or a background thread that waits for messages from the queue.
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 know that I can run a background process in python using subprocess. But the problem is that when I make a gui and then use subprocess with close_fds=True parameter, the window changes to not responding.
So, what I want is that I need to create a background process but it should run separately along with the main process and when that process is done, it should again combine with the main process.
BTW, I am using PySide2 as the gui framework
Any help would be appreciated
I think what would be more beneficial to you would be threading, you are able to start a process in another thread without blocking the main thread which runs your gui. Once the other thread has completed its task it will join the main thread
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 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 :)
Python have been really bumpy for me, because the last time I created a GUI client, the client seems to hang when spawning a process, calling a shell script, and calling outside application.
This have been my major problem with Python since then, and now I'm in a new project, can someone give me pointers, and a word of advice in order for my GUI python application to still be interactive when spawning another process?
Simplest (not necessarily "best" in an abstract sense): spawn the subprocess in a separate thread, communicating results back to the main thread via a Queue.Queue instance -- the main thread must periodically check that queue to see if the results have arrived yet, but periodic polling isn't hard to arrange in any event loop.
Your main GUI thread will freeze if you spawn off a process and wait for it to completely. Often, you can simply use subprocess and poll it now and then for completion rather than waiting for it to finish. This will keep your GUI from freezing.