So I've been having problems with Tkinter for Python 3 on MacOS 10.15.5. Here's the reproducible code for my system:
import tkinter as tk
import tkinter.messagebox as msgbox
def quit():
root.destroy()
root = tk.Tk()
lbl = tk.Label(root,text="This is a label.")
ent = tk.Entry(root)
btn = tk.Button(root,text="Quit", command=quit)
lbl.pack()
ent.pack()
btn.pack()
root.mainloop()
for i in range(800000):
print(i)
After I press "quit", the for loop runs in the background, but the Tkinter window freezes (with the spinning wheel), until the for loop concludes. I'm trying to create a program that takes user input at the beginning and then runs code in the background, so you can see why I'd rather not have the GUI frozen the whole time.
I'm running this code from the terminal, but I get the same issue using IDLE. I've tried uninstalling and reinstalling several different versions of python (from the python website, since apparently that's the way to use Tk properly), and this problem persists.
Weirdly enough, I've seen that adding an input statement, rather than any other code, immediately after the mainloop, will cause the window to close, but I can't figure out why, and it wouldn't really work with my broader program.
Related
In Tkinter I find a small problem. I am unable to use an Entry/Text/Scrolledtext/any widget that the user can enter letters into after using a Tkinter simpledialog prompt. The entry widget works fine before using the prompt, but after the prompt I am unable to enter stuff into the widget. It's as though the widget becomes disabled. No exception is thrown. However, I can access the widget again once I click on another window and click on my Tkinter window again.
I have tried using the focus_get method on the entry widget. It doesn't work.
I have also tried doing entry.config(state='normal'). That doesn't work.
I could not think of anything else to try. Searching the web doesn't work; nothing relevant comes up.
Here's some example code:
import tkinter as tk
import tkinter.simpledialog as dialog
def get_string():
string = dialog.askstring("Title", "Prompt")
print(string)
root = tk.Tk()
entry = tk.Entry(root)
button = tk.Button(root, text="Get String", command=get_string)
entry.pack()
button.pack()
root.mainloop()
For the problem to show, you need to click on the button, and then try to use the entry widget; it doesn't work for me.
I am using Python 3.9.6, on macOS.
Edit: after a few people commented, this problem is probably specific to macOS Big Sur; this problem isn't there on Windows, OSX, or Linux.
So, I left the project alone for a while, and now I've updated to macOS Monterey and Python 3.10. With these updates, I now find the problem disappeared.
I have created a program that is completely based on tkinter GUI, however it also uses a couple of other modules and non related things. So, when I close the window, the code is still being executed as tkinter isnt the only thing it uses. I have tried to fix it by doing:
import sys
def on_closing():
sys.exit()
root.protocol("WM_DELETE_WINDOW", on_closing)
However, if i try to exit the tkinter window with this code active, the entire program crashes. Is there any other perhaps more efficent solution?
I have made a GUI using Tkinter for my Python script for a Voice Assistant. It is working pretty well. But I want to add an animation window to display an animation that I have created using After Effects as an intro to the app. I want it to open without the default close(x), maximize and minimize buttons. The window should stay till the animation is completed, and then it would disappear. The main window would then open normally to launch the GUI. To disable the close, maximize and minimize buttons I have used the root.overrideredirect(True) method. But I am not being able to simultaneously open the two windows one after the other as mentioned. I would be highly obliged if somebody would help me out with this! I have tested it with a code on a simple GUI. I am providing the code below for help with the problem!
from tkinter import *
import time
root = Tk()
root.geometry('500x300')
root.overrideredirect(True) # To disable the default Window decoration
time.sleep(5) # Assuming that the animation runs for 5 seconds
root.destroy() # This window destroys after being on screen for 5 seconds
root.mainloop()
root2 = Tk() # After the previous window is destroyed, this window opens up. Assume that this is the main window
root2.geometry('500x300')
root.mainloop()
Please help me out!
The thing you call "animation window" is actually called "splash". There is a way to do what you want. You need to create a root window for the app (a Tk instance), and then you should hide (root.withdraw()) it. Now create a Toplevel for the splash, wait for 5 seconds, destroy it, and show (root.deiconify()) the Tk window again.
Note: time.sleep(5) should never be used with Tkinter, use root.after(ms, func) instead.
from tkinter import *
def show_splash():
splash = Toplevel()
splash.geometry('500x300')
splash.overrideredirect(True) # To disable the default Window decoration
splash.after(5000, splash.destroy) # This window destroys after being on screen for 5 seconds
splash.wait_window()
root = Tk()
root.withdraw()
show_splash()
root.deiconify()
root.mainloop()
PS: Procedural programming is not a good idea for pretty complex Tkinter-based apps. You should consider using OOP instead.
PPS: Take a look at this and this answers.
Could not find anything on this topic in other posts (or maybe I just completely did not understand how tkinter works).
I have a very simple setup where after closing my window, a Shell script is supposed to be executed. The problem (at least on MacOSX) is that while the shell script runs, the window freezes and stays open.
Minimal working example:
from tkinter import Tk, Label
from subprocess import call
# GUI
root=Tk()
Label(root,text="Test window").pack()
root.mainloop()
# call
call("sleep 10", shell=True)
# Window stays open and freezes until sleep command returns
Am I missing something?
Thanks! Jan
When I create a tkinter window instance using a thread, even though the window is destroyed after execution, and the thread is joined; I can't make another tkinter window later on in the program flow. Why?
def on_button_click(root): //destroys window on button click
root.destroy()
def init(): //thread calls this
root=Tk()
b = Button(root, text="OK", command=lambda:on_button_click(root))
b.pack()
root.mainloop()
t = Thread(target=init)
t.start()
t.join()
root=Tk() //program flow halts here with no window being displayed
root.mainloop()
From what I can gather using my Google-foo, the problem is that the Tk event loop (which is created during your call to root.mainloop()) is single-threaded and you can only have one instance of it at a time. So that's probably why its getting stuck at that location. Your thread is properly setting up the Tk subsystem but the program fails when you try to create a second Tk subsystem to run at the same time. Your call to root.destroy() is only destroying the windows that you created and not the entire Tk subsystem.
It's been a while since I used Tk but I'd suggest calling root.mainloop() once when you first start your program and then leave your functions to instantiate Tk windows only, not the entire Tk subsystem.