在 Python(tkinter)中从类的外部更改类的私有属性(标签)

Posted

技术标签:

【中文标题】在 Python(tkinter)中从类的外部更改类的私有属性(标签)【英文标题】:Changing private attributes (labels) of a Class from outside of it in Python (tkinter) 【发布时间】:2021-08-13 07:26:29 【问题描述】:

我在 Python 中使用 tkinter 制作了一个 GUI,我创建了一个名为“Window”的类来管理整个会话期间 GUI 中的所有创建、运行和更改。 我不知道我是否让这太复杂了,但我正在尝试构建一个方法,所以我只能从“Window”类中更改标签,并且因为有很多标签,我想做类似的东西下一个代码(这是一个最小的可重现示例):

from tkinter import *

class Window:
    def __init__(self, wind):
        self.__window = wind
        self.__window.geometry("200x100")
        self.__window.title("Title")

        self.__label_1 = Label(self.__window, text="Label 1 text")
        self.__label_1.pack()

        self.__button_1 = Button(self.__window, text="Change", command=function)
        self.__button_1.pack()

    def change_label(self, label, text): #this 'label' is the name of the label I want to change
        self.label["text"] = text        #here I try to use it as the attibute's name


def function():
    myWindow.change_label("__label_1", "New text")


if __name__=='__main__':
    wind = Tk()
    myWindow = Window(wind)
    wind.mainloop()

我面临的问题显然是:AttributeError, 'Window' object has no attribute 'label'。

有没有办法制作我想要制作的东西?将我要更改的标签名称发送给方法,然后接收它并将其视为属性名称?

或者我应该将标签声明为公共标签并从“Window”类之外更改它?

问题是标签很多,我不希望他们被错误地改变,所以我想“简化”改变的过程,但也许我把它弄得太复杂了。

提前感谢您的回复。

【问题讨论】:

您可以使用实例字典,例如self.__labels = ,来保存标签:self.__labels["__label_1"] = self.__label_1。然后使用这个字典来更新change_label()里面需要的标签。 谢谢@acw1668 我对 Python 还很陌生,所以我对“实例字典”感到困惑,我刚刚读了一些东西,但我还是不明白,我无法实现你的解决方案.您的意思是将标签的所有文本值存储在字典中并直接更改这些值吗?但是如何刷新 GUI 以使标签发生变化? 我的意思是类型为 dictionary 的类的实例变量,就像我之前评论中的示例:self.__labels = self.__labels 是实例变量,它的类型是dictionary Python 没有私有属性 这是双下划线名称修改。这与 private 不同,Python 没有任何访问修饰符 @juanpa.arrivillaga "__label_1" 只是一个字符串,用作字典中存储或引用标签的键。 【参考方案1】:

如果您想使用字符串访问小部件,您需要通过name 选项提供一个唯一名称。为了更容易访问,最好使用字典来存储小部件,使用它们的名称作为键。

以下是根据您的修改的示例:

from tkinter import *

class Window:
    def __init__(self, wind):
        self.__window = wind
        self.__window.geometry("200x100")
        self.__window.title("Title")

        self.__widgets =  # dictionary to hold the created widgets

        # use whatever "name" you want but it must be unique
        self.create(Label, text="Label 1 text", name="label_1")
        self.create(Button, text="Change", command=function, name="button_change")

    def create(self, widget, **kw):
        w = widget(self.__window, **kw)
        w.pack()
        name = kw.get("name", str(w)) # use implicitly created name if "name" option is not given
        self.__widgets[name] = w
        return name

    def change(self, name, **kw):
        self.__widgets[name].config(**kw)


def function():
    # access the widget using the unique name
    myWindow.change("label_1", text="New text", font="Arial 24 bold")


if __name__=='__main__':
    wind = Tk()
    myWindow = Window(wind)
    wind.mainloop()

【讨论】:

这正是我想做的,非常感谢!【参考方案2】:

这里有两个基本问题。 Python 没有私有属性。 Python 没有 any 访问修饰符。您在这里使用的是 双下划线名称修饰。这与私有相同。它只是将名称更改为 _MyClass__my_attribute 以防止子类中的意外名称冲突,它仍然可以从外部完全访问:

>>> class Foo:
...     def __init__(self):
...         self.__bar = 42
...
>>> foo = Foo()
>>> foo._Foo__bar
42

表示不属于公共 API 的变量的惯用方式是使用 单下划线,例如self._bar = 42,这可能是您应该在这里使用的

现在,这种方法永远行不通了:

def change_label(self, label, text): #this 'label' is the name of the label I want to change
    self.label["text"] = text        #here I try to use it as the attibute's name

你想要的方式。要使用字符串修改属性,请使用getattrsetattr

>>> class Foo: pass
...
>>> foo = Foo()
>>> setattr(foo, 'bar', 42)
>>> foo.bar
42
>>> getattr(foo, 'bar')
42

【讨论】:

以上是关于在 Python(tkinter)中从类的外部更改类的私有属性(标签)的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中从类外部访问私有构造函数

如何在颤动中从类(小部件外部)打开屏幕

react中从类重构为功能钩子组件

Python,从类外部访问小部件项

在 C# 中从类中声明一个数组

mule 在流程中从类路径中读取单个文件