Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm in the process of converting a simulation based application using simpy into a GUI.
The program currently runs within the console and the simpy which is doing the simulation runs by default in a loop like syntax. And that's where my issue seems to be.
Currently, within the console version of the code, I grab user input through the raw_input() function and that is able to interrupt the code and allow the user to input the values that the simulation desires. However, despite researching it, there does not seem to be a similar and clean way of doing this through pyqt inisde the GUI I'm building.
Would the only way be to run the processes in different threads? And if I were to do that approach, how exactly would that look and truly function?
PyQt is event-based. It's running a loop continuously waiting for events, and it calls your callbacks (or signals your slots) when it gets an event you care about. So, there's no way to directly say "block until I get input".
But, before you even get to that point, if your simulation is running a loop continuously in the main thread, PyQt can't also be running a loop continuously in the main thread. So it can't respond to events from the OS like "update your window" or "quit". As far as your user is concerned, the app is just frozen; she'll see nothing but the ever-popular beachball (or other platform equivalent).
And however you choose to solve that first problem will solve most of the second one almost for free.
Why your GUI app freezes attempts to explain the whole issue, and all of the possible solutions, in general terms, using Tkinter as an example of a GUI library. If you want something more Qt-specific, I'm pretty sure there's a whole section about it in the Qt tutorial, although I'm not sure where, and you may have to translate a bit of C++ to Python in your head.
But there are two major options: Callbacks, or threads.
First, you can break your loop up into small pieces, each of which only takes a few milliseconds. Instead of running the whole loop, you run the first piece, and as its last line, it asks PyQt to schedule the next piece as soon as possible (e.g., using a QTimer with a timeout of 0). Now, Qt will get to check for events every few milliseconds, and if it's got nothing to do, it will immediately kick off the next step of your work.
If your flow control is already built around an iterator (or push-coroutine) that yields appropriately-sized chunks, this is very easy. If not, it can mean turning the flow control in your outer loop inside-out, which can be hard to understand.
So, having done this, how do you get user input? Simple:
Where you would have called raw_input, instead of scheduling the next piece of your code, instead do some appropriate GUI stuff—create a popup messagebox, unhide a text entry control and button, whatever.
Connect the next piece of your code as a handler for the button-clicking or messagebox-accepting or whatever signal.
Alternatively, you can run your work in a background thread. This doesn't require you to reorganize anything, but it does require you to be careful not to share anything between threads. Unfortunately, this includes calling methods on GUI widgets from the background thread, which you'd think would make it impossible to do anything useful. Fortunately, PyQt has mechanisms to deal with that pretty easily: signals are automatically routed between threads as necessary.
So, how do you ask for user input in this scenario?
Split off everything after the raw_input into a separate function, which you connect as a handler for a got_input signal.
In the original function, where you used to call raw_input, you instead emit a gimme_input signal.
Write a handler for that gimme_input signal to run in the main thread, which will put up the GUI widgets (as with the single-threaded example above).
Write a handler for the OK button that emits the got_input signal back to the worker thread.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
As part of my end-of-studies' project I'm working on a GUI which basically takes input values and run calculation from them. My issue occurs when I push the button which run these calculation. I want this button to be disabled during the calculation and its text to change for showing that the GUI is busy.
Unfortunately, these changes are displayed on the GUI only when the calculation is over, not before and even if they are called before the function that runs the simulation in the code.
Therefore I was wondering how these instructions are proceeding so I can maybe understand what's going on underneath.
Here's a short extract of the code if you want it :
I call the function 'onButtonClicked' when I push it
self.pushButton_simu.clicked.connect(self.onButtonClicked)
Then this (shortened) function calls 'displayGraph' which will do the calculation and display the results
def onButtonClicked(self):
if (not self.exist and self.simu):
self.displayGraph()
Finally in this one I create a file where I put some values then try to disable and change the text of my button (which does not work immediately). Then I run the calculation with 'simu.simulation' and when it is over, my messagebox is displayed and so are my new text and my button disabled. Then when I close the messagebox the text changes immediately and my button becomes unable again.
def displayGraph(self):
with open("Input_simulation", 'wb') as dataFile:
pickle.dump([self.planete.reynolds(), self.planete.reynoldsMagnetique(), self.planete.stuart(), int(self.label_Vnbmode_2.text()), self.spinBox_pasmode.value()], dataFile)
self.pushButton_simu.setText("Simulation en cours")
self.pushButton_simu.setEnabled(False)
mode, wImMax = simu.simulation('Input_simulation')
infoBox = QtWidgets.QMessageBox()
infoBox.setIcon(QtWidgets.QMessageBox.Information)
infoBox.setWindowTitle("Information")
infoBox.setText("Simulation réussie")
infoBox.exec_()
self.pushButton_simu.setEnabled(True)
self.pushButton_simu.setText("Lancer la simulation")
I tried to add a 'time.sleep' between setText and the beginning of the simulation but it doesn't work at all so I really don't understand what's going on. It's like it's too busy by the simulation to display the changes.
EDIT : I fixed my issue by using that thanks to rbaleksandar :
QtCore.QCoreApplication.processEvents()
You need to run the calculations in a separate thread. Otherwise experience exactly what's happening in your case - your button gets blocked (in fact the whole UI is) since intensive calculations takes all the processing time of your main thread, where also the UI resides (along with all things related to it like drawing, event handling etc.). If the thread is busy calculating your stuff, it has no "time" left doing anything else.
Typically this is done by creating a QThread and pushing (using moveToThread(...)) of another object to it, where you actual calculations take place. This object is called the worker, while the thread - the worker thread. You can then connect a signal from your worker to your button or the widget that contains it and disable/enable it respectively.
Alternative to that solution you can go for QRunnable with a slight modification to enable it to actually send signals (since QRunnable is not actually a QObject-derived class hence you need to explicitly inherit from QObject in order to use slots and signals).
I am writing an app in kivy which does cpu-heavy calculations at launch. I want the app to display what it's doing at the moment along with the progress, however, since the main loop is not reached yet, it just displays empty white screen until it finishes working. Can I force kivy to update the interface?
Basically I'm looking for kivy's equivalent of Tkinter's root.update()
I could create a workaround by defining a series of functions with each calling the next one through Clock.schedule_once(nextFunction, 1), but that would be very sloppy.
Thanks in advance.
Leaving aside the question of whether you should be using threading or something instead (which possibly you should), the answer is just that you should move your cpu calculations to somewhere else. Display something simple initially (i.e. returning a simple widget from your build method), then do the calculations after that, such as by clock scheduling them.
Your calculations will still block the gui in this case. You can work around this by doing them in a thread or by manually breaking them up into small pieces that can be sequentially scheduled.
It might be possible to update the gui by manually calling something like Clock.tick(), but I'm not sure if this will work right, and even if so it won't be able to display graphics before they have been initialised.
I created an complete logger-type program, that logs the certain data from the internet sources. It's GUI I coded in wx.python, now I want to daemonize it (if it is the right term). The program needs to run in background and user has to have option to call/open GUI when he pleases. How can I achieve this with wx.python?
I wouldn't really "daemonize" it per se. Instead, I would just put it in the system tray...at least, that's what I would do on Windows. I assume you can do something similar on the other OSes. Basically you want to bind the frame to wx.EVT_ICONIZE and in that method, you hide it. Then when the user double-clicks the taskbar icon, you want to show it and probably Raise it too.
There's some badly formatted code here: http://bytes.com/topic/python/answers/699757-wxpython-how-minimize-taskbar (I've used a variation of it myself, so I know it works).
And here's some information on Task bar icons: http://www.blog.pythonlibrary.org/2011/12/13/wxpython-101-creating-taskbar-icons/
I've seen a lot of stuff about running code in subprocesses or threads, and using the multiprocessing and threading modules it's been really easy. However, doing this in a GUI adds an extra layer of complication.
From what I understand, the GUI classes don't like it if you try and manipulate them from multiple threads (or processes). The workaround is to send the data from whatever thread you created it in to the thread responsible for the graphics and then render it there.
Unfortunately, for the scenario I have in mind this is not an option: The gui I've created allows users to write their own plotting code which is then executed. This means I have no control over how they plot exactly, nor do I want to have it. (Update: these plots are displayed in separate windows and don't need to be embedded anywhere in the main GUI. What I want is for them to exist separated from the main GUI, without sharing any of the underlying stack of graphics libraries.)
So what I'm wondering now is
Is there some clean(ish) way of executing a string of python code in a whole new interpreter instance with its own ties to the windowing system?
In response to the comments:
The current application is set up as follows: A simple python script loads a wxPython gui (a wx.App). Using this gui users can set up a simulation, part of which involves creating a script in plain python that runs the simulation and post-processes the results (which usually involves making plots and displaying them). At the moment I'm doing this by simply calling exec() on the script code. This works fine, but the gui freezes while the simulation is running. I've experimented with running the embedded script in a subprocess, which also works fine, right up until you try to display the created graphs (usually using matplotlib's show()). At this point some library deep down in the stack of wxPython, wx, gtk etc starts complaining because you cannot manipulate it from multiple threads.
The set-up I would like to have is roughly the same, but instead of the embedded script sharing a GUI with the main application, I would like it to show graphics in an environment of its own.
And just to clarify:
This is not a question about "how do I do multithreading/multiprocessing" or even "how do I do multithreading/multiprocessing within a single wxpython gui". The question is how I can start a script from a gui that loads an entirely new gui. How do I get the window manager to see this script as an entirely separate application?
The easiest way would be to generate it in a temporary folder somewhere and then make a non-blocking call to the python interpreter, but this makes communication more difficult and it'd be quite hard to know when I could delete the temp files again. I was hoping there was a cleaner, dynamical way of doing this.
Can you simply use subprocess to run 'python.exe' and pipe the script in?
Alternatively, the multiprocessing package should suffice if you want to move some (pickle-able) data over to the new process in which you run the script. Just create a function/callable that runs the script, and create a Process object with the callable as target. That way, you should be able to pass some data over, without having GUI issues.
Capturing text with either is easy, subprocess allows that and no more. With multiprocess, you can pass python objects back and forth more easily.
On Windows, you can create window with a parent window from another process, and draw to that.
See the hWndParent argument to CreateWindowEx.
If wxWindows supports getting/setting that explicitly, then you should be good to go.
Depending on your platform, something similar might be possible in any windows system.
So, just giving your users the ability to find the handle of your apps window should give them the option to plot away at views embedded in your app, while running in their own processes.
I don't no much about wx, I work with jython(python implemented in java and you can use java) and swing. Swing has its own worker thread, and if you do gui updates you wrap your code into a runnable and invoke it with swing.invokelater.
You could see if wx has something like that, if you however are only allowed to manipulate the gui from the thread in which you created it try something similar. create a proxy object for your gui, which forwards all your calls to your thread which forwards them to the gui.
But proxying like this gets messy. how about you let them define classes, with an 'updateGui' function, that they should hand back to you over a queue and that you will execute in your gui thread.
In wxPython land when you use threads, you have to use its thread-safe methods to communicate with the GUI: wx.CallAfter, wx.CallLater or wx.PostEvent. In your case, I would run any long running code in a separate thread/process and when it's done its processing, send the result to the GUI. The GUI can instantiate a new frame and use matplotlib or PyPlot to show the plot, depending on which way you want to go. I've heard you can draw the plot using FloatCanvas too.
Anyway, if you instantiate the new frame correctly, then you can instantiate N frames and show them and be fine. See the wxPython wiki for a few examples of using Threads with wx: http://wiki.wxpython.org/LongRunningTasks
I'd like to know how to have a program wait for another program to finish a task. I'm not sure what I'd look for for that...
Also, I'm using a mac.
I'd like to use Python or perhaps even applescript (I could just osascript python if the solution if for applescript anyway)
Basically this program "MPEGstreamclip" converts videos, and it opens what appears to be 2 new windows while it's converting. One window is a conversion progress bar, and the other window is a preview of the conversion. (Not sure if these actually count as windows)
(Also, MPEGstreamclip does not have an applescript dictionary, so as far as I know, it can't listen for certain window names existence)
But basically I want my program to listen for when MPEGstreamclip is done, and then run its tasks.
If it helps, when the conversion is done, the mpegstreamclip icon in the dock bounces once. I'm not sure what that means but I'd think you could use that to trigger something couldn't you?
Thanks!
I realized GUI applescript was the answer in this scenario. With it I could tell the PROCESS to get every window, and that worked. However, I'm leaving this up because I'd like to know other ways. I'm sure this GUI workaround won't work for everything.
If the MPEGstreamclip actually ends when it is done, you could wrap the whole thing up in a python script using various techniques already discussed in another post. Just be sure to wait for the external process to end before continuing with your other steps.