I used to use the Interactive Editor for Python, and then I "upgraded" to Pyzo (since IEP was merged into Pyzo). One of my programs uses tkinter to create a GUI. The code used to work just fine: I would run the file as a script, and then, in the interpreter, I would call main, which would launch the application.
The code skeleton looks like this.
def main():
class Application(tk.Frame):
def __init__(self, master=None):
# a bunch of stuff
# several more methods here
front=Application()
front.mainloop()
# then I can either call main in the interpreter, or I can add this:
# the name==main part is to handle some multiprocessing that occurs within the application class
if __name__=="__main__":
main()
This worked like a charm in IEP. However, in Pyzo, main() never launches, or, rather, it launches, but the gui never appears and it doesn't let me do anything. Instead, I get this message: Note: The GUI event loop is already running in the pyzo kernel. Be aware that the function to enter the main loop does not block.
This message occurs in Pyzo when I am using the CPython 3 or PyPy interpreter, but not when I'm using Anaconda 3 (I actually need to use PyPy because the work I'm doing is computationally expensive).
The other alternative is to not use Pyzo, but that's no fun.
I discovered the answer a while ago but I didn't get back to posting the answer until now. Essentially, there is a setting in Pyzo itself which attempts to detect GUIs. Switching that setting from auto to none fixed the problem.
Related
I've been fighting with Tkinter for a while now and have exhausted most the resources I have for referencing this. I've found a couple similar topics here but none quite bring me to where I need to be.
I've got a long running (not long actually, it only takes 10-12 secs) python script that silently install an application using subprocess from the CLI. Subprocess worked and it successfully installed the application, however, the GUI locks (i.e hangs/freeze) after the execution (and the program no longer run the succeeding code). I know I have to use threading here but I've already tried using it to no avail.
As part of my learning process, I cloned a repo from Github and modify it to run on Windows (since it only run in MAC platform) and planning to extend it, and this is the part where I got stucked. This is my first time to use TKinter and I apologize if I have missed something stupid or not asked the question in the right way. Hope you can help me and thank you in advance for the assistance.
Code can be found on this link.
You have defined a button
installButton = Button(bottomFrame, text=installButtonTxt,
command=on_install_thread, width=9)
with command handler
def on_install_thread():
...
loop_thread = threading.Thread(target=on_install_button_active,
args=['button', 'model', itemSelectCount])
and the target for thread on_install_button_active.
Then
def on_install_button_active(button, model, selectcount):
...
# Reset install status
installStatus = 'complete'
# Remove Cancel Button
cancelButton.destroy()
# Activate Install/Done button and menus
installButton.configure(state=NORMAL)
# menuControl('normal')
refreshGui(mainWindow)
It looks like there is code at the end of on_install_button_active that involves Tkinter
widgets. Calling tkinter methods from other threads seems to be unreliable, for example 1.
It is possible to define virtual events
def renderMainWindow():
...
mainWindow.bind('<<InstallComplete>>', on_install_complete)
def on_install_complete():
cancelButton.destroy()
installButton.configure(state=NORMAL)
def on_install_button_active(button, model, selectcount):
...
# Reset install status
installStatus = 'complete'
mainWindow.event_generate('<<InstallComplete>>', when='tail')
If there are other calls in that thread that involve Tkinter widgets, it might be better to remove them.
I was able to resolved problems with my GUI by using mtTkinter and by referring to this post.
So I have a Tkinter application that I use at work. I wrote another Tkinter application that I wanted to call from the main Tkinter application. I know that Tkinter isn't 'thread safe', but I'm not 100% sure what that means. Does it mean that it can 'work', but it isn't guaranteed to work as written? Or should it just not work at all?
The reason I ask is because when I run the code below(self.thread_easy_imaging() is triggered by a filemenu option), it works just fine. So far I haven't encountered any issues and both GUIs are operational so far as I can tell. Is this because I'm using subprocess.call to call the script? I'm having a hard time wrapping my head around this because I know you can't use thread in a Tkinter app to do something like run a function while still being able to use buttons in the GUI, but for some reason when I use a thread to call the script with subprocess.call it does it just fine. When I wrote it, I assumed it wouldn't work, but for some odd reason it does. Here is an example of the code I'm using:
def thread_easy_imaging(self):
thread.start_new_thread(self.start_easy_imaging, ('EASY-IMAGING-1', 0))
def start_easy_imaging(self, thread_name, delay):
time.sleep(delay) #have to have args for some reason? I just did a delay of 0 seconds so I could use the tuple.
subprocess.call(['c:/python27/python.exe', 'EasyImaging.py'])
self.thread_easy_imaging()
I have only used this on a windows machine, but I'm guessing that it should work on any OS.
Edit: The scripts don't have to interact at all, I just want to add my other GUI application into the filemenu so I can call it as a separate application. If needed, I'll just use a Toplevel widget to recreate the application I want to call because it won't muck up the main thread at all.
Thanks in advance!
i am facing some understanding problems since i am trying do dive into pyqt´s gui programming.
I use
exec(open("./regression.py").read())
inside my pyqt gui program to call a script where my calculations are made after the user has pushed some buttons (these define some variables in regression.py)
so if i run this in an empty script all my definitions are callable (and i see them in the variable explorer).
if i try to run this in my gui program - the script executes but if i wanted to reuse one variable or a method i defined in the regression.py in another action of my gui it is not possible.
Everything is gone after execution.
...
self.connect(self.buttonOK,
QtCore.SIGNAL("clicked()"), self.onOK)
def onOK(self):
if self.button1.checkState():
a=3
if self.button2.checkState():
a=1
exec(open("./regression.py").read())# this scripts takes the value of "a" to run
# it prints some calculations - but everything is gone after pressing "OK" button
app = QtGui.QApplication(sys.argv)
dialog = MeinDialog()
dialog.show()
Why is that the case? how can i find a solution? is my method of spitting gui and actual calculations using modules like numpy and so on right?
exec is a python call. In PyQt you need to use exec_().
[edit] I read the question too quickly. I thought the problem was starting the eventloop, not getting variables from another process. Can you import your regression module and run it in process, instead of using exec?
So i am running into a major issue. I am currently trying to use multi-processing/sub-processing to run files next to my Tkinter application, however, as soon as I run the process, the GUI freezes until I finish the process. Is there any way to get around this? I have also looked at other questions on SO but to no avail (I found one suggesting root.update() however that is not working as expected.
Note: I have not included GUI elements, as I have made basic programs to try this (only a couple of lines) and get the same problem. It also may be worth noting that I am running windows.
code (taken out of context):
def run_file(self):
self.root.update()
sub_process=subprocess.call(self.sub_proc_args)
process=multiprocessing.Process(target=self.run_file())
process.start()
By doing self.run_file() you are calling run_file before multiprocessing can use it. You need to use target=self.run_file (note, without parentheses).
I have found the problem (other then the target issue that BrenBarn pointed out). Here is my fix:
(i took out the multiprocessing.)
def run_file(self):
sub_process=subprocess.Popen(self.sub_proc_args) #Open subprocess
self.root.update() #Update GUI
self.run_file() #Initiate sub_process
I have found that this is the fix because using call, when you execute it, it must return a return value, which makes Tkinter not continue its mainloop. This is fixed by using Popen.
If I'm trying to create a window or prompt a file dialog in the IDLE shell, nothing opens and the shell restarts. Is this a bug of some kind? I can't find anything about it. I'm new to PyQt (and Python in general) but had been able to get tutorials to work correctly. The last day or so, if I open IDLE and import PyQt4, QtGui, etc and then run something simple like QFileDialog.getOpenFileName, the shell just restarts. Any ideas?
You need to have a QApplication before you can use anything else from PyQt. Try rereading some of the tutorials you followed, or do a few more. This one for example.
In the first code sample of the above tutorial, pay special attention to these lines (I've included the comments from the tutorial for convenience):
app = QtGui.QApplication(sys.argv)
Every PyQt4 application must create an application object. The
application object is located in the QtGui module. The sys.argv
parameter is a list of arguments from the command line. Python scripts
can be run from the shell. It is a way, how we can control the startup
of our scripts.
and
sys.exit(app.exec_())
Finally, we enter the mainloop of the application. The event handling
starts from this point. The mainloop receives events from the window
system and dispatches them to the application widgets. The mainloop
ends, if we call the exit() method or the main widget is destroyed.
The sys.exit() method ensures a clean exit. The environment will be
informed, how the application ended.
The exec_() method has an underscore. It is because the exec is a
Python keyword. And thus, exec_() was used instead.
It appears you might have forgotten about these. Or maybe you haven't realized that this means that you normally can't use PyQt with a running event loop in the interactive shell. However, there is a trick for that, see here.