【问题标题】:How can I modify a variable being used in one class from another class by using tkinter?如何使用 tkinter 从另一个类修改一个类中使用的变量?
【发布时间】:2020-03-07 09:21:11
【问题描述】:

我想要完成的是一种在另一个类实例中更改变量的方法。我一直在摸索,试图了解这是如何(或是否)可能的。

如何更新类中self.lblvar 的值 MainWindow 来自班级SecondWindow

这是我用来检验我的理论的东西:

from tkinter import *

class MainWindow:
    def __init__(self, rootWin):
        self.rootWin = rootWin
        self.rootWin.geometry('400x200')

        self.mainMenu = Menu(self.rootWin)
        self.mainMenu.add_command(label = 'Open Second Window', command = self.openSecondWindow)

        self.lblvar = StringVar()
        self.lblvar.set('Change Me!')
        self.lbl = Label(rootWin, textvariable = self.lblvar)
        self.lbl.pack()

        self.rootWin.config(menu = self.mainMenu)

    def openSecondWindow(self):
        self.secondWin = Tk()
        self.secWin = SecondWindow(self)
        self.secondWin.mainloop()

class SecondWindow:
    def __init__(self, parent):
        self.parent = parent

        self.btn = Button(self, label = 'Change Label?', command = self.changeOther)
        self.btn.pack()

    def changeOther(self):
        self.parent.lblvar.set('Changed it!')

def main():
    root = Tk()
    mainWin = MainWindow(root)
    root.mainloop()

if __name__ == "__main__":
    main()

在 Python 类方面我是个新手,所以任何有关这方面的指导和/或解释都将不胜感激!

编辑:将原始问题更改为更清晰的问题,以帮助对该主题进行进一步搜索

【问题讨论】:

  • 抱歉,没有更多关于您要完成的工作的解释,您的问题不清楚。
  • 嘿@ThierryLathuille!我想要完成的是创建一个辅助“选项”窗口来调整主窗口。在这种情况下,第二个窗口仅对主窗口的标签对象进行更改。
  • 您是在寻找 Tkinter 特定的答案(即我可以更改其他窗口中的属性吗?),或者天气这个概念在 python 中是否可行?
  • @Aleon 是正确的。我正在尝试在另一个 Tkinter 窗口中修改标签和其他对象
  • @Aleon 如果他们修复了openSecondWindow,OP 应该可以正常工作。这种方法并没有像他们认为的那样做。虽然我会重写它以继承 TkToplevel 以解决其他一些问题。

标签: python class tkinter class-attributes


【解决方案1】:

因此,让您的代码按预期工作所需的最小更改是更改您的类 SecondWindow 以接受 2 个参数,一个用于顶级窗口,一个用于主窗口类,以及更改方法openSecondWindow 使用Toplevel 窗口而不是Tk 的第二个实例,因为您不应该在tkinter GUI 中使用多个Tk() 实例。一个小问题是您在按钮内部使用了label =,而这实际上应该是text=。这样我们就可以使用 class 属性了。

类似这样的:

def openSecondWindow(self):
    self.secondWin = Toplevel(self.rootWin)
    self.secWin = SecondWindow(self.secondWin, self)

class SecondWindow:
    def __init__(self, top, master):
        self.master = master

        self.btn = Button(top, text='Change Label?', command=self.changeOther)
        self.btn.pack()

    def changeOther(self):
        self.master.lblvar.set('Changed it!')

也就是说,我会整体更改一些内容以提高可读性并减少代码行数。

  1. import tkinter as tk 而不是使用*。这将有助于防止覆盖内置方法/其他导入,并明确您在代码中使用的库。

  2. 从您的班级中的Tk()Toplevel() 继承,以使事情更容易处理。

  3. 仅在需要的地方使用self.。您代码中的某些地方不需要这样做。

请参阅下面的修改示例,如果您有任何问题,请告诉我:

import tkinter as tk


class MainWindow(tk.Tk):
    def __init__(self):
        # super is used to avoid referring to the base class explicitly.
        # to read more on this check out the link below.
        super().__init__()
        self.geometry('400x200')
        main_menu = tk.Menu(self)
        self.config(menu=main_menu)
        main_menu.add_command(label='Open Second Window', command=SecondWindow)
        self.lblvar = tk.StringVar(value='Change Me!')
        # No need to use `self.` on this label as we are working with the lblvar in the 2nd window and not the label.
        tk.Label(self, textvariable=self.lblvar).pack()


class SecondWindow(tk.Toplevel):
    def __init__(self):
        super().__init__()
        # No need to use `self.` on this button unless down the road you want to change this button in some way.
        tk.Button(self, text='Change Label?', command=self.change_other).pack()

    def change_other(self):
        # with inheriting like this in tkinter you do not need to define self.master as it is automatic here.
        # Other classes or methods may need it defined however. Just wanted to make sure you are aware of this.
        self.master.lblvar.set('Changed it!')


if __name__ == "__main__":
    MainWindow().mainloop()

结果:

更多详情请关注super()

【讨论】:

  • 哇!这正是我正在寻找的!我想我需要进一步研究我创建的类是如何从另一个类继承的。我希望在我从事一些个人 Python 项目以获得良好的工作知识时能够更好地掌握这一点。感谢您对我的编码风格提出建设性的批评,以获得更易读的版本。
  • @TheJFo 很高兴为您提供帮助。所以类继承所做的是给你的类你继承的类的所有属性和方法。这无疑是一个有用的工具。
【解决方案2】:

是的。完全可以从另一个类中修改一个类的状态或一个类的实例。与 C++ 等传统 OOP 语言不同,Python 不强制执行任何访问规则——一切都是公开的。

class ClassA:
    def __init__(self, var_a):
        self.var_a = var_a

    def change_var_c(self, instance_b, new_value):
        instance_b.var_c = new_value

    def change_var_b(self, new_value):
        ClassB.VAR_B = new_value

class ClassB:
    VAR_B = 2
    def __init__(self, var_c):
        self.var_c = var_c


instance_a = ClassA(1)
instance_b = ClassB(3)

instance_a.change_var_c(instance_b, 4)
print(instance_b.var_c) # prints 4

instance_a.change_var_b(5)
print(ClassB.VAR_B) # prints 5

不过,这可能不是您应该做的事情。修改对象的内部违反了封装的原则。类应该改为公开一个公共接口来修改它们的“私有”成员。

【讨论】:

  • “与 Java 等传统 OOP 语言不同”有趣的是,Python 是一种比 Java 稍的 OOP 语言。我想你可以说不像 C++,这在当时是等价的。但访问修饰符实际上并不是 OOP 语言的特征。只是很多人认为“OOP”的意思是“像 Java 一样做”。
  • 如何在该实例中创建公共接口?另一方面,如果我还想走这条路,我应该只在 MainWindow 类中定义它吗?
  • @TheJFo 通过公共接口,我只是指MainWindow 类上的方法集合。因此,您将在您的MainWindow 类上定义一个def set_label_text(self, text):,例如,这将是self.lblvar.set(text)。然后可以访问MainWindow 对象的类可以调用此方法来更改标签的文本,例如。 main_window.set_label_text("New text").
  • @mario_sunny,那么您是否建议将此辅助窗口放在 MainWindow 类中并在必要时调用它?似乎调用另一个班级是完成我所追求的事情的迂回方式。
猜你喜欢
  • 1970-01-01
  • 2013-09-17
  • 2014-10-06
  • 2021-08-08
  • 1970-01-01
  • 2018-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多