Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

grab_set in tkinter window

Tags:

python

tkinter

I've seen many examples of grab_set() being used for modal windows for tkinter but I can't get it to work for my application. I am creating a second window as my 'Settings' window which is called from the Menu of the main application.

example:

import tkinter as tk

class Main(tk.Tk):

    def __init__(self,*args, **kwargs):
        tk.Tk.__init__(self,*args, *kwargs)

        button = tk.Button(self,text="second window", command=lambda:Settings())
        button.pack()


class Settings(tk.Tk):

    def __init__(self,*args, **kwargs):
        tk.Tk.__init__(self,*args, *kwargs)
        button = tk.Button(self,text="quit", command=lambda: quit())
        button.pack()
        self.grab_set()

if __name__ == "__main__":
    app = Main()
    app.mainloop()

Right now I can still click the 'Settings' button to create as many instances of Settings as the pc would allow. How do I restrict clickability to the main application window until the second one is closed first?

like image 679
Ernie Peters Avatar asked Oct 28 '25 05:10

Ernie Peters


2 Answers

Here is a super simple example of how you can open another window using Toplevel and how you can edit stuff on the main window from the Toplevel window.

Its very basic but it should be a good enough example to illustrate what is required in tkinter to open new window.

UPDATE: Added the grab_set() method as pointed out by Bryan in the comments.

The grab_set() method according to the documentation routes all events for this application to this widget.

Note: This would be along the lines of a Minimal, Complete, and Verifiable example. It is the smallest possible bit of code to get the point across while also being testable.

from tkinter import *


class GUI(Frame):
    def __init__(self, master, *args, **kwargs):
        Frame.__init__(self, master, *args, **kwargs)
        
        self.master = master
        self.my_frame = Frame(self.master)
        self.my_frame.pack()

        self.button1 = Button(self.master, text="Open New Window", command = self.open_toplevel_window)
        self.button1.pack()
        
        self.text = Text(self.master, width = 20, height = 3)
        self.text.pack()
        self.text.insert(END, "Before\ntop window\ninteraction")
        
    def open_toplevel_window(self):
        self.top = Toplevel(self.master)
        #this forces all focus on the top level until Toplevel is closed
        self.top.grab_set() 
        
        def replace_text():
            self.text.delete(1.0, END)
            self.text.insert(END, "Text From\nToplevel")
        
        top_button = Button(self.top, text = "Replace text in main window",
                            command = replace_text)
        top_button.pack()


if __name__ == "__main__":
    root = Tk()
    app = GUI(root)
    root.mainloop()

Here is an example when using a separate class for the Toplevel:

from tkinter import *


class GUI(Frame):
    def __init__(self, master, *args, **kwargs):
        Frame.__init__(self, master, *args, **kwargs)
        
        self.master = master
        self.my_frame = Frame(self.master)
        self.my_frame.pack()

        self.button1 = Button(self.master, text="Open New Window",
                              command = open_toplevel_window)
        self.button1.pack()
        
        self.text = Text(self.master, width = 20, height = 3)
        self.text.pack()
        self.text.insert(END, "Before\ntop window\ninteraction")
        
class open_toplevel_window(Toplevel):
    def __init__(self, *args, **kwargs):
        Toplevel.__init__(self, *args, **kwargs)
        self.grab_set()
        
        def replace_text():
            app.text.delete(1.0, END)
            app.text.insert(END, "Text From\nToplevel")
        
        top_button = Button(self, text = "Replace text in main window",
                            command = replace_text)
        top_button.pack()


if __name__ == "__main__":
    root = Tk()
    app = GUI(root)
    root.mainloop()
like image 112
Mike - SMT Avatar answered Oct 30 '25 22:10

Mike - SMT


Try adding the following line after the line containing the grab_set method:

self.wait_window(self)
like image 35
Marcelo Vai Avatar answered Oct 30 '25 23:10

Marcelo Vai