I am learning about Tkinter and was wondering if it would cause errors if I did the following:
import tkinter as tk #import modules
from tkinter import ttk
parent=tk.Tk() #create first instance
card1="k spades"
card2="k diamonds"
comboform=ttk.Combobox(parent,textvariable='form',values=[card1,card2,"both","neither"])#create combobox input form
comboform.grid(row=0,column=0)#added to grid
parent.geometry("200x200")
parent.mainloop()#displays tkinter window
#window exited
parent=tk.Tk()#new instance created
label=tk.Label(parent,text="hi")#label produced
label.pack()#added to window
parent.mainloop()
If I click the exit cross is that the same as parent.destroy(); is that good practice? I know you're only supposed to run mainloop() once and have one Tk() instance but if it's destroyed is it going to cause problems? It's not like I'm creating a class the produces a Tk() instance, where there's a risk of multiple instances existing at once.
I am hoping to, eventually, have an application running in the IDLE and then have a tkinter window appear, presenting an input widget of some kind. After the user gives their input, the window would close and the user would continue in the main window. But could I then do it again, opening new windows (like the above code) on the provision that the instance of Tk() is destroyed each time?
If you've destroyed the root window and then create a new one, that's perfectly fine.
The problem with creating multiple instances of Tk is that most people don't understand what that actually does. Having multiple instances of Tk is fine as long as you realize that they operate in completely memory spaces and widgets and bindings in one can't interact with widgets and bindings in the other.
All of that being said, the best practice is to create a single root window at the start of the program, and it stays alive until the program exits. If you need additional windows, the best practice is to create instances of Toplevel.
Related
Consider below example:
import tkinter as tk
root = tk.Tk()
root.title("root")
other_window = tk.Tk()
other_window.title("other_window")
root.mainloop()
and also see below example that creates instances of Tk back-to-back instead of at once, so there's exactly one instance of Tk at any given time:
import tkinter as tk
def create_window(window_to_be_closed=None):
if window_to_be_closed:
window_to_be_closed.destroy()
window = tk.Tk()
tk.Button(window, text="Quit", command=lambda arg=window : create_window(arg)).pack()
window.mainloop()
create_window()
Why is it considered bad to have multiple instances of Tk?
Is the second snippet considered a bit better, or does it suffer from
the same conditions the first code does?
Why is it considered bad to have multiple instances of Tk?
Tkinter is just a python wrapper around an embedded Tcl interpreter that imports the Tk library. When you create a root window, you create an instance of a Tcl interpreter.
Each Tcl interpreter is an isolated sandbox. An object in one sandbox cannot interact with objects in another. The most common manifestation of that is that a StringVar created in one interpreter is not visible in another. The same goes for widgets -- you can't create widgets in one interpreter that has as a parent widget in another interpreter. Images are a third case: images created in one cannot be used in another.
From a technical standpoint, there's no reason why you can't have two instances of Tk at the same time. The recommendation against it is because there's rarely an actual need to have two or more distinct Tcl interpreters, and it causes problems that are hard for beginners to grasp.
Is the second snippet considered a bit better, or does it suffer from the same conditions the first code does?
It's impossible to say whether the second example in the question is better or not without knowing what you're trying to achieve. It probably is not any better since, again, there's rarely ever a time when you actually need two instances.
The best solution 99.9% of the time is to create exactly one instance of Tk that you use for the life of your program. If you need a second or subsequent window, create instances of Toplevel. Quite simply, that is how tkinter and the underlying Tcl/Tk interpreter was designed to be used.
I disagree with the tkinter community discouraging the use of multiple tk.Tk windows. You can have multiple tk.Tk windows. Using multiple instances of tk.Tk is the only way to create windows that are truly independent of each other. The only mistake most people make when creating multiple tk.Tk windows is that they forget to pass in master=... when creating PhotoImages/StringVars/IntVars/...
For example look at this code:
import tkinter as tk
root = tk.Tk()
root2 = tk.Tk()
variable = tk.StringVar() # Add `master=root2` to fix the problem
entry = tk.Entry(root2, textvariable=variable)
entry.bind("<Return>", lambda e: print(repr(variable.get())))
entry.pack()
root.mainloop()
The code above doesn't work. If you add master=root2 to the tk.StringVar(), then it will work perfectly fine. This is because tkinter stores the first instance of tk.Tk() in tk._default_root. Then if you don't pass in master=..., it will assume that you wanted the window in tk._default_root.
Another thing people get wrong is how many times should .mainloop() be called. It handles events from all tk.Tk windows that are alive so you only need one .mainloop().
For folks who disagree, I'd be interested in an example of where an actual problem is caused by the multiple tk.Tk windows.
The best reference I've found so far is the Application Windows section of the tkinterbook:
In the simple examples we’ve used this far, there’s only one window on the screen; the root window. This is automatically created when you call the Tk constructor
and
If you need to create additional windows, you can use the Toplevel widget. It simply creates a new window on the screen, a window that looks and behaves pretty much like the original root window
My take on it is that a Tk instance creates a Toplevel widget, plus things like the mainloop, of which there should be only one.
Tk() initializes the hidden tcl interpreter so that the code can run, as Tkinter is just a wrapper around tcl/tk. It also automatically creates a new window. Toplevel() just creates a new window, and wont work if Tk() hasn't been instantiated, as it requires the tcl interpreter that Tk() initializes. You cannot create any Tkinter widgets without instantiating Tk(), and Toplevel is merely a widget. In the question, you use Tk() to create a second window. You should instead create another file, because initializing the tcl interpreter multiple times can get confusing, as #Bryan Oakley explains so well. Then you should do:
from os import startfile
startfile(nameOfTheOtherFile)
, because, as Toplevel() is just a widget, it closes when the Tk() window is closed. Having the other window in a separate file makes it less confusing.
Consider below example:
import tkinter as tk
root = tk.Tk()
root.title("root")
other_window = tk.Tk()
other_window.title("other_window")
root.mainloop()
and also see below example that creates instances of Tk back-to-back instead of at once, so there's exactly one instance of Tk at any given time:
import tkinter as tk
def create_window(window_to_be_closed=None):
if window_to_be_closed:
window_to_be_closed.destroy()
window = tk.Tk()
tk.Button(window, text="Quit", command=lambda arg=window : create_window(arg)).pack()
window.mainloop()
create_window()
Why is it considered bad to have multiple instances of Tk?
Is the second snippet considered a bit better, or does it suffer from
the same conditions the first code does?
Why is it considered bad to have multiple instances of Tk?
Tkinter is just a python wrapper around an embedded Tcl interpreter that imports the Tk library. When you create a root window, you create an instance of a Tcl interpreter.
Each Tcl interpreter is an isolated sandbox. An object in one sandbox cannot interact with objects in another. The most common manifestation of that is that a StringVar created in one interpreter is not visible in another. The same goes for widgets -- you can't create widgets in one interpreter that has as a parent widget in another interpreter. Images are a third case: images created in one cannot be used in another.
From a technical standpoint, there's no reason why you can't have two instances of Tk at the same time. The recommendation against it is because there's rarely an actual need to have two or more distinct Tcl interpreters, and it causes problems that are hard for beginners to grasp.
Is the second snippet considered a bit better, or does it suffer from the same conditions the first code does?
It's impossible to say whether the second example in the question is better or not without knowing what you're trying to achieve. It probably is not any better since, again, there's rarely ever a time when you actually need two instances.
The best solution 99.9% of the time is to create exactly one instance of Tk that you use for the life of your program. If you need a second or subsequent window, create instances of Toplevel. Quite simply, that is how tkinter and the underlying Tcl/Tk interpreter was designed to be used.
I disagree with the tkinter community discouraging the use of multiple tk.Tk windows. You can have multiple tk.Tk windows. Using multiple instances of tk.Tk is the only way to create windows that are truly independent of each other. The only mistake most people make when creating multiple tk.Tk windows is that they forget to pass in master=... when creating PhotoImages/StringVars/IntVars/...
For example look at this code:
import tkinter as tk
root = tk.Tk()
root2 = tk.Tk()
variable = tk.StringVar() # Add `master=root2` to fix the problem
entry = tk.Entry(root2, textvariable=variable)
entry.bind("<Return>", lambda e: print(repr(variable.get())))
entry.pack()
root.mainloop()
The code above doesn't work. If you add master=root2 to the tk.StringVar(), then it will work perfectly fine. This is because tkinter stores the first instance of tk.Tk() in tk._default_root. Then if you don't pass in master=..., it will assume that you wanted the window in tk._default_root.
Another thing people get wrong is how many times should .mainloop() be called. It handles events from all tk.Tk windows that are alive so you only need one .mainloop().
For folks who disagree, I'd be interested in an example of where an actual problem is caused by the multiple tk.Tk windows.
The best reference I've found so far is the Application Windows section of the tkinterbook:
In the simple examples we’ve used this far, there’s only one window on the screen; the root window. This is automatically created when you call the Tk constructor
and
If you need to create additional windows, you can use the Toplevel widget. It simply creates a new window on the screen, a window that looks and behaves pretty much like the original root window
My take on it is that a Tk instance creates a Toplevel widget, plus things like the mainloop, of which there should be only one.
Tk() initializes the hidden tcl interpreter so that the code can run, as Tkinter is just a wrapper around tcl/tk. It also automatically creates a new window. Toplevel() just creates a new window, and wont work if Tk() hasn't been instantiated, as it requires the tcl interpreter that Tk() initializes. You cannot create any Tkinter widgets without instantiating Tk(), and Toplevel is merely a widget. In the question, you use Tk() to create a second window. You should instead create another file, because initializing the tcl interpreter multiple times can get confusing, as #Bryan Oakley explains so well. Then you should do:
from os import startfile
startfile(nameOfTheOtherFile)
, because, as Toplevel() is just a widget, it closes when the Tk() window is closed. Having the other window in a separate file makes it less confusing.
Consider below example:
import tkinter as tk
root = tk.Tk()
root.title("root")
other_window = tk.Tk()
other_window.title("other_window")
root.mainloop()
and also see below example that creates instances of Tk back-to-back instead of at once, so there's exactly one instance of Tk at any given time:
import tkinter as tk
def create_window(window_to_be_closed=None):
if window_to_be_closed:
window_to_be_closed.destroy()
window = tk.Tk()
tk.Button(window, text="Quit", command=lambda arg=window : create_window(arg)).pack()
window.mainloop()
create_window()
Why is it considered bad to have multiple instances of Tk?
Is the second snippet considered a bit better, or does it suffer from
the same conditions the first code does?
Why is it considered bad to have multiple instances of Tk?
Tkinter is just a python wrapper around an embedded Tcl interpreter that imports the Tk library. When you create a root window, you create an instance of a Tcl interpreter.
Each Tcl interpreter is an isolated sandbox. An object in one sandbox cannot interact with objects in another. The most common manifestation of that is that a StringVar created in one interpreter is not visible in another. The same goes for widgets -- you can't create widgets in one interpreter that has as a parent widget in another interpreter. Images are a third case: images created in one cannot be used in another.
From a technical standpoint, there's no reason why you can't have two instances of Tk at the same time. The recommendation against it is because there's rarely an actual need to have two or more distinct Tcl interpreters, and it causes problems that are hard for beginners to grasp.
Is the second snippet considered a bit better, or does it suffer from the same conditions the first code does?
It's impossible to say whether the second example in the question is better or not without knowing what you're trying to achieve. It probably is not any better since, again, there's rarely ever a time when you actually need two instances.
The best solution 99.9% of the time is to create exactly one instance of Tk that you use for the life of your program. If you need a second or subsequent window, create instances of Toplevel. Quite simply, that is how tkinter and the underlying Tcl/Tk interpreter was designed to be used.
I disagree with the tkinter community discouraging the use of multiple tk.Tk windows. You can have multiple tk.Tk windows. Using multiple instances of tk.Tk is the only way to create windows that are truly independent of each other. The only mistake most people make when creating multiple tk.Tk windows is that they forget to pass in master=... when creating PhotoImages/StringVars/IntVars/...
For example look at this code:
import tkinter as tk
root = tk.Tk()
root2 = tk.Tk()
variable = tk.StringVar() # Add `master=root2` to fix the problem
entry = tk.Entry(root2, textvariable=variable)
entry.bind("<Return>", lambda e: print(repr(variable.get())))
entry.pack()
root.mainloop()
The code above doesn't work. If you add master=root2 to the tk.StringVar(), then it will work perfectly fine. This is because tkinter stores the first instance of tk.Tk() in tk._default_root. Then if you don't pass in master=..., it will assume that you wanted the window in tk._default_root.
Another thing people get wrong is how many times should .mainloop() be called. It handles events from all tk.Tk windows that are alive so you only need one .mainloop().
For folks who disagree, I'd be interested in an example of where an actual problem is caused by the multiple tk.Tk windows.
The best reference I've found so far is the Application Windows section of the tkinterbook:
In the simple examples we’ve used this far, there’s only one window on the screen; the root window. This is automatically created when you call the Tk constructor
and
If you need to create additional windows, you can use the Toplevel widget. It simply creates a new window on the screen, a window that looks and behaves pretty much like the original root window
My take on it is that a Tk instance creates a Toplevel widget, plus things like the mainloop, of which there should be only one.
Tk() initializes the hidden tcl interpreter so that the code can run, as Tkinter is just a wrapper around tcl/tk. It also automatically creates a new window. Toplevel() just creates a new window, and wont work if Tk() hasn't been instantiated, as it requires the tcl interpreter that Tk() initializes. You cannot create any Tkinter widgets without instantiating Tk(), and Toplevel is merely a widget. In the question, you use Tk() to create a second window. You should instead create another file, because initializing the tcl interpreter multiple times can get confusing, as #Bryan Oakley explains so well. Then you should do:
from os import startfile
startfile(nameOfTheOtherFile)
, because, as Toplevel() is just a widget, it closes when the Tk() window is closed. Having the other window in a separate file makes it less confusing.
i am having issue with the tkinter StrinVar() and i dont have much knowledge in tkinter and would like some help, thanks.
What i have done is i created two window in which each has a Entry widget and Button widget if you click button of one window then that window gets withdraw and another window pop ups and if you click button in that pop up window then it withdraws and a original window gets pop up.Here is the code:-
from tkinter import *
def x():
a1.set("")
a.withdraw()
b.deiconify()
def y():
b1.set("")
b.withdraw()
a.deiconify()
a=Tk()
a.withdraw()
a1=StringVar()
b1=StringVar()
Entry(a,textvariable=a1).pack()
Button(a,text="button1",command=x).pack()
a.withdraw()
b=Tk()
Entry(b,textvariable=b1).pack()
Button(b,text="button2",command=y).pack()
mainloop()
if you write something in entry widget and press button2 then second window pop ups then again if you write something in entry widget and press button1 the entry field is not getting updated in previous first window.
i found that someone suggested that there should not be two instanses of Tk() a tkinter must have only one instanse of Tk() for multiple window use Toplevel(). So, i changed b=Tk() to b=Toplevel() which works fine and StringVar() was updating value
Now, my question is that 1)What is the reason/logic behind not updating StingVar() with two instanses of Tk()2) is there any way to make StringVar() to update value with having two instanses of Tk()
" Tkinter is just a python wrapper around an embedded Tcl interpreter that imports the Tk library. When you create a root window, you create an instance of a Tcl interpreter.
Each Tcl interpreter is an isolated sandbox. An object in one sandbox cannot interact with objects in another. The most common manifestation of that is that a StringVar created in one interpreter is not visible in another. The same goes for widgets -- you can't create widgets in one interpreter that has as a parent widget in another interpreter.
From a technical standpoint, there's no reason why you can't have two instances of Tk at the same time. The recommendation against it is because there's rarely an actual need to have two or more distinct Tcl interpreters, and it causes problems that are hard for beginners to grasp.
The best solution 99.9% of the time is to create exactly one instance of Tk that you use for the life of your program. Quite simply, that is how tkinter and the underlying Tcl/Tk interpreter was designed to be used. " --- From Bryan Oakley at Why are multiple instances of Tk discouraged?
#1 So When you create a=Tk() and then b=Tk() StringVar a1, b1 is available in b=Tk() but not in a=Tk(). that's why value is not updating in a=Tk().
#2 As stated above "StringVar created in one interpreter is not visible in another". So is there no way to make StringVar() to update value with having two instanses of Tk().
I am having a problem between the python shell in my IDE and the Tkinter window. What I am trying to do is have all of my user input in the shell, and then I would like to output the corresponding information in a Tkinter window.
However, when my window is made and pops up, I close it to continue my program in the shell, then I continue with input. However, when I try to reinitialize my window. It says that the window has been destroyed. I understand what this means so I tried having a Toplevel window where I output my info which can be closed, and hide my root window, but the shell will not continue until I close/destroy the root window as well.
Is there a way I can continue in the shell without destroying my root window? I am fairly new to this language so any help would be very much appreciated.
This is my general idea:
from Tkinter import *
#get all my info from the shell
root = Tk()
root.withdraw() #hide the root window
main = Toplevel()
#this is the window that I want to be able to close and open later
#get more info from the shell after main is closed
#now I want to open the updated main window
Thanks in advance! (And I am working on Windows if that matters)
I'm not sure if the way you are trying to do this is the most efficient way, but i would propose these changes so far:
from Tkinter import *
#get all my info from the shell
window = Tk()
window.iconify() #hide the root window
#get more info from the shell after main is closed
window.deiconify()
window.mainloop() # to handle events
i renamed your root-Window to make it more clear for you whats happening and removed the superflous (imho) additional Toplevel-window!
Also keep in mind, that you won't accomplish anything without the mainloop and the necessary event-handlers!
Simply put, this is not how Tkinter is designed to work. Tkinter was designed to have a single root window that is created once, and with a single eventloop that is running. Using it any other way is bound to lead to undesired behavior.
If you really need code to work this way, gather your input from your shell in one process, then use a separate process to display the tkinter window. You can either communicate from one the other using a socket, or you could pass the data from the parent to the child via arguments or environment variables or temporary files.