Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to gray out (disable) a tkinter Frame?

I want to create a GUI in tkinter with two Frames, and have the bottom Frame grayed out until some event happens.

Below is some example code:

from tkinter import *
from tkinter import ttk

def enable():
    frame2.state(statespec='enabled') #Causes error

root = Tk()

#Creates top frame
frame1 = ttk.LabelFrame(root, padding=(10,10,10,10))
frame1.grid(column=0, row=0, padx=10, pady=10)

button2 = ttk.Button(frame1, text="This enables bottom frame", command=enable)
button2.pack()

#Creates bottom frame
frame2 = ttk.LabelFrame(root, padding=(10,10,10,10))
frame2.grid(column=0, row=1, padx=10, pady=10)
frame2.state(statespec='disabled') #Causes error

entry = ttk.Entry(frame2)
entry.pack()

button2 = ttk.Button(frame2, text="button")
button2.pack()

root.mainloop()

Is this possible without having to individually gray out all of the frame2's widgets?

I'm using Tkinter 8.5 and Python 3.3.

like image 300
Big Sharpie Avatar asked Jul 24 '14 19:07

Big Sharpie


2 Answers

Not sure how elegant it is, but I found a solution by adding

for child in frame2.winfo_children():
    child.configure(state='disable')

which loops through and disables each of frame2's children, and by changing enable() to essentially reverse this with

def enable(childList):
    for child in childList:
        child.configure(state='enable')

Furthermore, I removed frame2.state(statespec='disabled') as this doesn't do what I need and throws an error besides.

Here's the complete code:

from tkinter import *
from tkinter import ttk

def enable(childList):
    for child in childList:
        child.configure(state='enable')

root = Tk()

#Creates top frame
frame1 = ttk.LabelFrame(root, padding=(10,10,10,10))
frame1.grid(column=0, row=0, padx=10, pady=10)

button2 = ttk.Button(frame1, text="This enables bottom frame", 
                     command=lambda: enable(frame2.winfo_children()))
button2.pack()

#Creates bottom frame
frame2 = ttk.LabelFrame(root, padding=(10,10,10,10))
frame2.grid(column=0, row=1, padx=10, pady=10)

entry = ttk.Entry(frame2)
entry.pack()

button2 = ttk.Button(frame2, text="button")
button2.pack()

for child in frame2.winfo_children():
    child.configure(state='disable')

root.mainloop()
like image 89
Big Sharpie Avatar answered Oct 20 '22 22:10

Big Sharpie


Based on @big Sharpie solution here are 2 generic functions that can disable and enable back a hierarchy of widget (frames "included"). Frame do not support the state setter.

def disableChildren(parent):
    for child in parent.winfo_children():
        wtype = child.winfo_class()
        if wtype not in ('Frame','Labelframe'):
            child.configure(state='disable')
        else:
            disableChildren(child)

def enableChildren(parent):
    for child in parent.winfo_children():
        wtype = child.winfo_class()
        print (wtype)
        if wtype not in ('Frame','Labelframe'):
            child.configure(state='normal')
        else:
            enableChildren(child)
like image 43
Jean-Marc Volle Avatar answered Oct 20 '22 22:10

Jean-Marc Volle