首页 > 解决方案 > tkinter.LabelFrame 与 Checkbutton labelwidget

问题描述

tkinter中,我想要一个类似于 的框架LabelFrame,但带有 aCheckbutton作为标签。

阅读LabelFrame 源代码后,我看到了该labelwidget选项并尝试了

checkbutton = tk.Checkbutton(text=text)
checkbutton_frame = tk.LabelFrame(window, labelwidget=checkbutton)

它在视觉上有效,但Checkbutton最终成为window( window.winfo_children()) 的子级。或者:

checkbutton_frame = tk.LabelFrame(window)
checkbutton = tk.Checkbutton(checkbutton_frame, text="Hello, frame")
checkbutton_frame.configure(labelwidget=checkbutton)

使. Checkbutton_ LabelFrame默认的,内置的Label不会LabelFrame出现在winfo_children. 因为我在添加所有小部件后设置padxpady递归,所以通过将Checkbuttonin移出其锚定位置来winfo_children破坏布局。Checkbutton有没有一种很好的、​​干净的方法来代替保持一致(即没有任何)后代关系CheckbuttonLabelin ?LabelFrame欢迎提供其他解决方法的答案。

最小的繁殖

import tkinter as tk

def pack_configure_recursive(widget, **kwargs):
    stack = list(widget.winfo_children())
    while stack:
        descendent = stack.pop()
        try:
            stack.extend(descendent.winfo_children())
        except Exception:
            pass
        try:
            descendent.pack_configure(**kwargs)
        except Exception:
            pass


class CheckbuttonFrame(tk.LabelFrame):
    def __init__(self, master=None, **kwargs):
        def pop_kwarg(name):
            nonlocal kwargs
            if name in kwargs:
                result = kwargs[name]
                del kwargs[name]
                return result
            else:
                return None

        text = pop_kwarg("text")
        self.variable = pop_kwarg("variable")
        self.command = pop_kwarg("command")

        tk.LabelFrame.__init__(self, master, **kwargs)
        self.configure(labelwidget=tk.Checkbutton(text=text, variable=self.variable, command=self.handler))  # Use this to make a child of the window
        # self.configure(labelwidget=tk.Checkbutton(self, text=text, variable=self.variable, command=self.handler))  # Use this to make a child of the frame

    def update_state(self):
        if self.variable:
            state = 'normal' if self.variable.get() else 'disable'
            stack = list(self.winfo_children())
            while stack:
                descendent = stack.pop()
                try:
                    stack.extend(descendent.winfo_children())
                except Exception:
                    pass
                try:
                    descendent.configure(state=state)
                except tk.TclError:
                    pass

    def handler(self):
        self.update_state()

        if self.command:
            external_command = self.command
            external_command()


window = tk.Tk()
option = tk.IntVar()
checkbutton_frame = CheckbuttonFrame(window, text="My option group", variable=option)
checkbutton_frame.pack()
tk.Label(checkbutton_frame, text="More widgets here").pack()
checkbutton_frame.update_state()
pack_configure_recursive(window, padx=2, pady=2)  # This line break the layout
window.mainloop()

标签: python-3.xtkinter

解决方案


LabelFrame 的默认内置标签不会出现在 winfo_children 中

那是因为 的内置标签LabelFrame不是小部件。

有没有一种很好、干净的方法来用一个 Checkbutton 代替 LabelFrame 中保持一致(即没有任何)后代关系的标签?欢迎提供其他解决方法的答案。

不,那里没有。小部件必须是某物的后代,根本无法绕过它。从逻辑上讲,它可能应该是 labelframe 本身的后代。

您必须自动重新打包小部件的任何代码都需要跳过此小部件。

您要调用的代码pack_configure可能应该忽略任何不由 pack 管理的小部件,您可以这样做:

if descendent.winfo_manager() == "pack":
    descendent.pack_configure(**kwargs)

推荐阅读