【问题标题】:Override class where mutliple kwargs are used in different functions覆盖在不同功能中使用多个 kwarg 的类
【发布时间】:2021-11-08 14:07:51
【问题描述】:

我希望覆盖 Tkinter Frame、Button、Lable 和 Entry 小部件,以将它们创建并打包在同一行代码中。 (IMO 2 行来执行此操作并获取 obj 的引用是丑陋的、低效的且难以阅读,即使它提供了更多的灵活性)。

我之前的代码是这样的:

   def cFrame(self, element, bg="white", borderwidth=0, relief="groove", side=None, padx=0, pady=0, height=0, width=0, expand=0, fill=None, image=None, highlightbackground=None, highlightcolor=None, highlightthickness=0, ipadx=0, ipady=0):
        f = self.TkUtil.Frame(element, bg=bg, borderwidth=borderwidth, relief=relief, height=height, width=width, image=image, highlightbackground=highlightbackground, highlightcolor=highlightcolor, highlightthickness=highlightthickness)
        f.pack(side=side, padx=padx, pady=pady, ipadx=ipadx, ipady=ipady, expand=expand, fill=fill)
        return f

我建议的课程如下所示:

class cFrame(Frame):
    def __init__(self, master, **kwargs):
        Frame.__init__(*(self, master), **kwargs)
        self.pack(**kwargs)

这是 **kwargs 的问题不关心关键字是否有效并返回 'bad option -"kwarg"'。

我已经尝试进一步扩展该功能,但我一直遇到问题:

class cButton(Button):
    def __init__(self, master,  **kwargs):
        Button.__init__(*(self, master))
        self.conf(**kwargs)
    def conf(self, **kwargs ):
        __pk_ops = {}
        for k, v in kwargs.items():
            try:
                self.configure({k:v})
            except:
                __pk_ops[k] = v
        self._pk(__pk_ops)
    def _pk(self, __ops):
        self.pack(__ops)

在这段代码中,我必须在之前遍历所有 kwargs 并单独配置它们,这在所需的 1000 个小部件上浪费了很多时间。此外,我遇到self.configure(text="sometext") 错误的问题,因此“文本”被传递给self.pack() 方法,因为出于某种神奇的原因,它特别不喜欢该选项(本示例中的化合物也一样)。

我的最终目标是将x = Frame(root, bg="black") \n x.pack(side=TOP) 替换为x = cFrame(root, bg="black", side=TOP) 而不默认任何选项,例如我当前的代码,使任何更改变得困难并且几乎不可能进行任何更改。

【问题讨论】:

  • 为什么不用合成函数def pack(widget, **kwargs): widget.pack(**kwargs); return widget;然后你可以做self.frame = pack(TkUtil.frame(..., bg=...), side=...)。这适用于任何小部件,而不仅仅是 cButton、cFrame、...
  • 我加倍它的相关性,但你为什么使用...(*(self, master), ...) 而不仅仅是...(self, master, ...)?创建一个元组只是为了立即解包它并没有什么意义。
  • 不过,问题似乎在于您没有区分__init__ 预期的关键字参数和pack 预期的关键字参数。您可能需要传递两个单独的 dict 参数,每个参数都作为关键字参数发送到相应的函数。
  • @Scott 你在找东西吗like this?

标签: python tkinter


【解决方案1】:

您可以创建一个自定义类来覆盖pack(),如下所示:

def cWidget:
    def pack(self, **kw):
        super().pack(**kw)  # call original pack()
        return self   # return widget itself

    # can do the same for grid() and place()

然后创建自定义小部件类如下:

import tkinter as tk

class cButton(cWidget, tk.Button): pass
# do the same for other widgets you want

现在您可以使用如下自定义按钮类:

...

root = tk.Tk()

def clicked():
    print('Button clicked')
    btn['text'] = 'Clicked'  # can use 'btn' to change its text as well

btn = cButton(root, text='Click me!', command=clicked, bg='gold').pack(padx=10, pady=10)
print(f'{btn=}')  # here you won't get None
print(isinstance(btn, tk.Button))  # here you get True
...

请注意,对于 Python 3.8+,您可以简单地使用 Walrus Operator (:=):

(btn := tk.Button(root, text='Click me!')).pack(padx=5, pady=5)

【讨论】:

  • 同样为了一次性提供给所有小部件,您可以定义自己的pack 函数,该函数将返回self 并将其分配给tk.Widget:tk.Widget.pack_configure = your_pack
猜你喜欢
  • 1970-01-01
  • 2020-02-11
  • 1970-01-01
  • 2017-03-17
  • 1970-01-01
  • 1970-01-01
  • 2017-03-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多