5

I have one problem. I have program which has been wrote on Tkinter.

import Tkinter as tk
import ttk


def about_window():
    print(root.child_window)

    if not root.child_window:
        top2 = tk.Toplevel(root)
        top2.title("About")
        top2.resizable(0,0)

        explanation = "This program is my test program"

        ttk.Label(top2,justify=tk.LEFT,text=explanation).pack(padx=5,pady=2)
        ttk.Button(top2,text='OK',width=10,command=top2.destroy).pack(pady=8)


root = tk.Tk()
root.resizable(0,0)

root.child_window = None
#print(root.child_window)

root.style = ttk.Style()
# ('clam', 'alt', 'default', 'classic')
root.style.theme_use("clam")

menu = tk.Menu(root)
root.config(menu=menu)

fm = tk.Menu(menu, tearoff=0)
menu.add_cascade(label="Settings",menu=fm)
fm.add_command(label="Preferances")

hm = tk.Menu(menu, tearoff=0)
menu.add_cascade(label="Help",menu=hm)
hm.add_command(label="About", command=about_window)
hm.add_command(label="Exit",command=root.quit)
#

tk.mainloop()

So I can click on "About" label and will see window:

enter image description here

But is it possible in Tkinter to disable any next launch of the same window?

enter image description here

I`ve tried this https://stackoverflow.com/a/24886806/2971192 but w/o success.

Community
  • 1
  • 1
ipeacocks
  • 2,187
  • 3
  • 32
  • 47
  • 1
    There are 2 ways to do this, do you want the user to be able to interact with your main window while 'About' is open or no? – MrAlexBailey Mar 24 '15 at 12:49
  • Jkdc, could you show two ways? – ipeacocks Mar 24 '15 at 12:53
  • What does "w/o success" mean? Do you get errors? Do you get multiple windows in spite of the `if` statement? The general pattern is correct: create the window the first time, then just make it visible after that. This is a very common technique. – Bryan Oakley Mar 24 '15 at 13:52

4 Answers4

7

The easiest way to make your about window modal is afaik adding the follwing lines to your about_window() function:

top2.focus_set()                                                        
top2.grab_set()    

the first line sets the focus to your about window,

the second line prohibits any other window to accept events.

Don Question
  • 11,227
  • 5
  • 36
  • 54
7

One way is to make the child window transient to the root, so that you cannot interact with root until the child has been closed ( you don't need root.child_window here):

import Tkinter as tk
import ttk

def about_window(): 
    top2 = tk.Toplevel(root)
    top2.title("About")
    top2.resizable(0,0)

    explanation = "This program is my test program"

    ttk.Label(top2,justify=tk.LEFT,text=explanation).pack(padx=5,pady=2)
    ttk.Button(top2,text='OK',width=10,command=top2.destroy).pack(pady=8)

    top2.transient(root)
    top2.grab_set()
    root.wait_window(top2)

root = tk.Tk()
root.resizable(0,0)

root.style = ttk.Style()
# ('clam', 'alt', 'default', 'classic')
root.style.theme_use("clam")

menu = tk.Menu(root)
root.config(menu=menu)

fm = tk.Menu(menu, tearoff=0)
menu.add_cascade(label="Settings",menu=fm)
fm.add_command(label="Preferances")

hm = tk.Menu(menu, tearoff=0)
menu.add_cascade(label="Help",menu=hm)
hm.add_command(label="About", command=about_window)
hm.add_command(label="Exit",command=root.quit)
#

tk.mainloop()
MrAlexBailey
  • 5,219
  • 19
  • 30
  • 2
    afaik `transient` is more a hint for the WM to establish a child - parent relationship, so the WM does not e.g. show the about window in a taskbar, or minimizes the about window, when the parent gets minified. It's probably a good idea, but modality is done through `grab_set` afaik. – Don Question Mar 24 '15 at 13:11
2

The other method is made a lot easier by using a Class to represent your program. It essentially boils down to the need for a global (or scope of the class instance) variable. In this case we use self.top2 which can be accessed inside and outside the method about_window().

This method will allow for full interaction with the root window while the child window is open.

import Tkinter as tk
import ttk


class MyProgram():

    def __init__(self):

        self.top2 = None
        self.root = root = tk.Tk()
        root.resizable(0,0)

        root.style = ttk.Style()
        # ('clam', 'alt', 'default', 'classic')
        root.style.theme_use("clam")

        menu = tk.Menu(root)
        root.config(menu=menu)

        fm = tk.Menu(menu, tearoff=0)
        menu.add_cascade(label="Settings",menu=fm)
        fm.add_command(label="Preferances")

        hm = tk.Menu(menu, tearoff=0)
        menu.add_cascade(label="Help",menu=hm)
        hm.add_command(label="About", command=self.about_window)
        hm.add_command(label="Exit",command=root.quit)

    def about_window(self):
        try:
            self.top2.focus_set()
            return
        except Exception:
            pass

        self.top2 = top2 = tk.Toplevel(self.root)
        top2.title("About")
        top2.resizable(0,0)

        explanation = "This program is my test program"

        ttk.Label(top2,justify=tk.LEFT,text=explanation).pack(padx=5,pady=2)
        ttk.Button(top2,text='OK',width=10,command=top2.destroy).pack(pady=8)


MyProgram()
tk.mainloop()
MrAlexBailey
  • 5,219
  • 19
  • 30
1

state(newstate=None)

Returns the window's current state, one of:

    'normal': Displayed normally.

    'iconic': Iconified with the .iconify() method.

    'withdrawn': Hidden; see the .withdraw() method below.
Raymond
  • 40
  • 8