omitting Toplevel's parent argument - python

I was checking out Toplevel of tkinter. From what I've seen from effbot I can omit its parent argument.
1- When I only use Toplevel itself (commenting out root), it creates its own parent I believe since two windows appear and only destroys one after clicking button.
2- If I don't comment out Tk(), it works fine. Two windows, one root - one toplevel and destroys toplevel.
3- If I interchange root and toplevel, first toplevel creates two again(like in first case), then root will create another so three windows will appear and only toplevel gets destroyed.
import tkinter as tk
#root = tk.Tk()
top = tk.Toplevel()
#root.title("Foo")
top.title("Bar")
top.geometry("300x100")
tk.Button(top, text = "Destroy", command=top.destroy).pack()
top.mainloop()
Question is, is there a way to create toplevel before Tk() and get only one window or access its parent and destroy it?
p.s. I found these two questions Toplevel in Tkinter: Prevent Two Windows from Opening && tkinter child window opens two windows?. First question is in 2nd case which is not what I want, and second question has no answer yet and his problem kind of not reproducable.
Also, I tried to get its master value -to destroy is manually- like this but seems like that value is not stored in dictionary where options are stored.
btn = tk.Button(top, text = "Destroy", command=top.destroy)
btn.pack()
print (btn["text"])
>>> Destroy
print (btn["master"])
>>> _tkinter.TclError: unknown option "-master"

It's not that Toplevel creates it's own parent, any widget will create a root window if you don't create one first. There simply must be a root window before any other widget can exist -- that's why it's called a root window. So, to answer your specific question, no, there is no way to create an instance of Toplevel without creating a root window first.

Related

Closing multiple toplevels in tkinter

I have created a tkinter application where the user can make multiple toplevel windows and have the option of closing them from inside the toplevel. I would like to make a button on the main window that closes all toplevel windows. How would I do this? Is there a way to do this without lists? If these toplevels are parts of classes is there also a way to call a function present in all of them?
Here's how to do the first part of your question about making a button in the main window to delete all the Toplevels without making a list of them. This works by using the universal winfo_children() widget method to find all the child widgets of the root (main) window.
It's unclear to me what you meant about calling a function present in all of them — Toplevel widgets are instances of a predefined tkinter class which supports a predefined set of methods — and you can call them the same way the sample code below does with child.destroy().
import tkinter as tk
root = tk.Tk()
root.title('Main')
root.geometry('200x100')
def close_all(master):
for child in master.winfo_children():
if isinstance(child, tk.Toplevel):
child.destroy() # Call method.
button = tk.Button(root, text=f"Close Toplevels",
command=lambda master=root: close_all(master))
button.pack()
for i in reversed(range(4)): # Create them bottom to top.
toplevel = tk.Toplevel()
toplevel.title(f'Toplevel {i+1}')
toplevel.geometry('200x75')
toplevel.lift()
button = tk.Button(toplevel, text="Close me", command=toplevel.destroy)
button.pack()
root.mainloop()

How to put a toplevel window in front of the main window in tkinter?

Is there any way to put a toplevel window in front of the main window?
Here's the code:
from tkinter import *
root = Tk()
root.geometry('1280x720')
def create_new_window():
root2 = Toplevel()
root2.geometry('500x500')
create_new_window()
mainloop()
Here, I want the root2 window to always stay in front of the root window.
I tried using root2.attributes('-topmost' , 1), but the problem is that this line puts the window on top of all the other programs as well.
What I want is that the toplevel window should only be in front of the main window, and it should never go back when I click on the main window.
Is there any way to achieve this in tkinter?
It would be great if anyone could help me out.
What you want, i think, is a transient window, you nedd to do:
root2.wm_transient(root)
From the manual:
wm transient window ?master?
If master is specified, then the window manager is informed that window is a transient window (e.g. pull-down menu) working on behalf of master (where master is the path name for a top-level window). If master is specified as an empty string then window is marked as not being a transient window any more. Otherwise the command returns the path name of window's current master, or an empty string if window isn't currently a transient window. A transient window will mirror state changes in the master and inherit the state of the master when initially mapped. It is an error to attempt to make a window a transient of itself.
So you could do something like this, but it seems buggy for me.
What I have done is to bind the FocusOut event to the toplevel that was created, so every time it looses the focus it triggers the event stackingorder to put the windos in the right order. You may need to expire this code for several events of your choice, but to get you the idea..
Here is the code:
import tkinter as tk
def add_toplevel(idx, toplevel):
if idx == 'end':
idx = len(toplevels)
toplevels.insert(idx,toplevel)
def create_new_window():
root2 = tk.Toplevel()
root2.geometry('500x500')
add_toplevel('end',root2)
root2.bind('<FocusOut>', stackingorder)
def stackingorder(event):
for toplevel in toplevels:
toplevel.lift()
toplevel.update_idletasks()
toplevels = [] #stacking order by index
root = tk.Tk()
create_new_window()
root.mainloop()
You are maybe also intrested in this:
https://stackoverflow.com/a/10391659/13629335

tkinter: immediately selecting newly opened window

The code is simple. In tkinter I create a button which opens a new window. The difference in the pictures below might be hard to see but if you look closely you can see that in the first picture the root window is selected even though it's behind the new opened window.
In my actual program I use keybindings to operate the second window so it would be nice to instantly select this window so you don't have to click on it to use keys to operate it. How can I select the Toplevel window as soon as it opens?
from tkinter import *
def open_new_window():
top = Toplevel(root)
root = Tk()
Button(root, text="open new window", command=open_new_window).pack()
root.mainloop()
Possible duplicate of this question
Like acw1668 said, simply add top.focus() at the end of your function open_new_window
Your new open_new_window function will look like this:
def open_new_window():
top = Toplevel(root)
top.focus()

Python tkinter checkbutton value always equal to 0

I put the checkbutton on the text widget, but everytime I select a checkbutton, the function checkbutton_value is called, and it returns 0.
Part of the code is :
def callback():
file_name=askopenfilename()
column_1rowname,column_name=draw_column(file_name)
root = Tk()
root.resizable(width=False,height=False)
root.wm_title("Column")
S = Scrollbar(root,orient="vertical")
text=Text(root,width=15,height=10,yscrollcommand=S.set)
S.config(command=text.yview)
S.pack(side="right",fill="y")
text.pack(side="left",fill="both",expand=True)
#check the value of the checkbutton
def checkbutton_value():
if(var.get()):
print 1
else:
print 0
var=BooleanVar()
chk = Checkbutton(root, text=column_1rowname[1], variable=var, command=checkbutton_value)
text.window_create("end", window=chk)
text.config(state=DISABLED)
errmsg='Error!'
Button(text='File Open',command=callback).pack(fill=X)
mainloop()
The problem is that you have more than one root window. You should only ever create exactly one instance of Tk, and call mainloop exactly once. If you need additional windows, create instances of Toplevel.
Each root window (and all of its children, and all related StringVars etc.) start a new, independent tcl interpreter. Widgets and variables associated with this window can't be used in another tcl interpreter. In your case, the StringVar is associated with the first root window, but the widget is associated with the second. You can't share data between root windows like that.

How to make Toplevel() widget appear above main root window?

I have made a Toplevel widget but when it pops up it always appears below my root window. Is there an easy way I can make it come to the top most level when it pops up?
you can use the .lift() method on a Toplevel widget:
import tkinter
root = tkinter.Tk()
root.title("root")
top = tkinter.Toplevel(root)
top.title("top")
top.lift(root)
root.mainloop()
according to this documentation you should be able to just use top.lift() to raise above all other windows but it didn't seem to work for me.
Edit: calling top.lift() without arguments does work when called during the mainloop, although since this question was specifically when starting the program that isn't very useful.
try attributes
import tkinter
root = tkinter.Tk()
root.title("root")
top = tkinter.Toplevel(root)
top.attributes('-topmost', 'true')
top.title("top")
root.mainloop()

Categories

Resources