有没有办法让tkinter的Frame变灰(禁用)?

13 投票
4 回答
28209 浏览
提问于 2025-04-18 14:39

我想用tkinter创建一个图形界面,里面有两个框架(Frame),并且希望底下的框架在某个事件发生之前是灰色的,不能使用。

下面是一些示例代码:

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()

这样做有没有可能,不用一个个把第二个框架里的小部件(widgets)都变成灰色?

我使用的是Tkinter 8.5和Python 3.3。

4 个回答

0

根据@Jean-Marc Volle的解决方案,我把他的两个函数合并成了一个函数,这个函数可以接收一个布尔值参数。同时,我还创建了一个函数,用来启用单个小部件,如果这个小部件是一个框架,就会调用第一个函数:

def enable_children(parent, enabled=True):
    for child in parent.winfo_children():
        wtype = child.winfo_class()
        print(wtype)
        if wtype not in ('Frame', 'Labelframe', 'TFrame', 'TLabelframe'):
            child.configure(state=tk.NORMAL if enabled else tk.DISABLED)
        else:
            enable_children(child, enabled)


def enable_widget(widget, enabled=True):
    wtype = widget.winfo_class()
    if wtype not in ('Frame', 'Labelframe', 'TFrame', 'TLabelframe'):
        widget.configure(state=tk.NORMAL if enabled else tk.DISABLED)
    else:
        enable_children(widget, enabled)

使用方法如下: enable_widget(widget) 用来启用这个小部件 enable_widget(widget, False) 用来禁用它。

你可能想把它放在一个包装器里使用:

def enable_my_widget(enabled=True):
    enable_widget(my_widget, enabled)

一张图片胜过千言万语: 下面是一个单独标签、一个框架和一个包含两个子框架的框架的图片:

禁用的标签

禁用的框架

禁用的框架和子框架

0

我觉得你可以一次性把整个框架隐藏起来。
如果你使用的是网格布局(grid)

 frame2.grid_forget()

如果你使用的是打包布局(pack)

 frame2.pack_forget()

在你的情况下,函数应该是

 def disable():
     frame2.pack_forget()

要重新启用它

def enable():
    frame2.pack()

grid_forget()pack_forget() 可以用于几乎所有的 tkinter 组件,这是一种简单的方法,可以减少你的代码长度,我相信这样做是有效的。

9

根据@big Sharpie 的解决方案,这里有两个通用的函数,可以用来禁用和重新启用一系列的控件(包括框架)。需要注意的是,框架本身不支持状态设置。

def disableChildren(parent):
    for child in parent.winfo_children():
        wtype = child.winfo_class()
        if wtype not in ('Frame','Labelframe','TFrame','TLabelframe'):
            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','TFrame','TLabelframe'):
            child.configure(state='normal')
        else:
            enableChildren(child)
20

我不太确定这个方法有多优雅,但我找到了一种解决方案,就是添加了

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

这个代码会循环遍历并禁用frame2里的每一个子元素,然后把enable()的功能基本上反转成

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

此外,我还去掉了frame2.state(statespec='disabled'),因为这个并不能满足我的需求,而且还会报错。

这是完整的代码:

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()

撰写回答