【问题标题】:Python and Tkinter: How to set a StringVar from a different classPython 和 Tkinter:如何从不同的类设置 StringVar
【发布时间】:2019-09-27 14:33:16
【问题描述】:

我正在学习一些 python 和 tkinter,并尝试了一个非常简单的示例应用程序。

一个 tkinter GUI、一个显示文本的标签和下面的 2 个按钮。 这些按钮应该更改标签中的文本,因为它通过 textvariable 参数链接到 StringVar...

应该发生什么,简单地说: 按“A”按钮,标签上将显示“A” 按“B”按钮,标签上会显示“B”

但是当我按下按钮“A”时,程序给了我 NameError: name 'display_frame' is not defined.

无法弄清楚发生了什么。我正在访问对象属性...

obs:由于按钮A有问题,未尝试配置按钮B的功能


import tkinter

class TkinterWindow(tkinter.Tk):
    def __init__(self):
        super().__init__()
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.configure(background='orange')



class DisplayFrame(tkinter.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.configure(background='cyan')
        self.grid(row=0, column=0, pady=5, padx=5, sticky='nsew')

        self.text = tkinter.StringVar()
        self.text.set('Hello')
        self.display = tkinter.Label(self, textvariable=self.text, font=15, bg="#bebebe", relief="groove", bd=5, height=5 )
        self.display.grid(sticky='nsew')

class ButtonsFrame(tkinter.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.configure(background='green')
        self.grid(row=1, column=0, pady=5, padx=5, sticky='nsew')

        self.button_A = tkinter.Button(self, text='A', command=self.write_A)
        self.button_A.grid(row=0, column=0, padx=15, sticky='nsew')

        self.button_B = tkinter.Button(self, text='B')
        self.button_B.grid(row=0, column=1, padx=15, sticky='nsew')

    def write_A(self):
        display_frame.text.set('A')


def main():
    window = TkinterWindow()
    display_frame = DisplayFrame(window)
    buttons_frame = ButtonsFrame(window)
    window.mainloop()


main()

【问题讨论】:

  • 如果您将display_frame 全球化,那么它会起作用,但这不是推荐的方法。正确的做法是在DisplayFrameButtonsFrame 之间建立连接以访问彼此的属性。

标签: python-3.x tkinter


【解决方案1】:

您遇到的主要问题是类属性self.text 对其他类不可见。解决此问题的一种方法是将该变量移动到主 tk 类,然后仅引用它。这是对您的代码的最快修复。

import tkinter

class TkinterWindow(tkinter.Tk):
    def __init__(self):
        super().__init__()
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.configure(background='orange')
        self.text = tkinter.StringVar()
        self.text.set('Hello')


class DisplayFrame(tkinter.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.configure(background='cyan')
        self.grid(row=0, column=0, pady=5, padx=5, sticky='nsew')


        self.display = tkinter.Label(self, textvariable=self.master.text, font=15, bg="#bebebe", relief="groove", bd=5, height=5 )
        self.display.grid(sticky='nsew')

class ButtonsFrame(tkinter.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.configure(background='green')
        self.grid(row=1, column=0, pady=5, padx=5, sticky='nsew')

        self.button_A = tkinter.Button(self, text='A', command=self.write_A)
        self.button_A.grid(row=0, column=0, padx=15, sticky='nsew')

        self.button_B = tkinter.Button(self, text='B')
        self.button_B.grid(row=0, column=1, padx=15, sticky='nsew')

    def write_A(self):
        self.master.text.set('A')


def main():
    window = TkinterWindow()
    display_frame = DisplayFrame(window)
    buttons_frame = ButtonsFrame(window)
    window.mainloop()

main()

也就是说,您的代码中有一些您应该注意的事情。在不需要时过度使用self.,并且在框架类中应用几何管理也是一个坏主意。

就我个人而言,我会在一个班级中完成所有这些。

import tkinter as tk


class TkinterWindow(tk.Tk):
    def __init__(self):
        super().__init__()
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.configure(background='orange')

        self.text = tk.StringVar()
        self.text.set('Hello')

        display_frame = tk.Frame(self, background='cyan')
        ButtonsFrame = tk.Frame(self, background='green')
        display_frame.rowconfigure(0, weight=1)
        display_frame.columnconfigure(0, weight=1)
        ButtonsFrame.rowconfigure(0, weight=1)
        ButtonsFrame.columnconfigure(0, weight=1)
        ButtonsFrame.columnconfigure(1, weight=1)

        display_frame.grid(row=0, column=0, pady=5, padx=5, sticky='nsew')
        ButtonsFrame.grid(row=1, column=0, pady=5, padx=5, sticky='nsew')

        tk.Label(display_frame, textvariable=self.text, font=15,
                 bg="#bebebe", relief="groove", bd=5).grid(row=0, column=0, sticky='nsew')

        tk.Button(ButtonsFrame, text='A',
                  command=lambda: self.update_text('A')).grid(row=0, column=0, padx=15, sticky='nsew')
        tk.Button(ButtonsFrame, text='B',
                  command=lambda: self.update_text('B')).grid(row=0, column=1, padx=15, sticky='nsew')

    def update_text(self, value):
        self.text.set(value)

TkinterWindow().mainloop()

【讨论】:

  • > 您遇到的主要问题是类属性 self.text 对其他类不可见。我对此有点困惑......我不是通过对象访问 self.text 吗?
  • > 在框架类中应用几何管理也是一个坏主意。好的,这有什么问题以及在哪里应用网格管理代码?
  • @BrunoLemos 在您的示例内部 display_frame 不在全局命名空间中,仅在函数 main 的本地命名空间中。因此,当您的方法 write_A 尝试查找 display_frame 时,它首先在本地查找 write_A 并且因为它没有在那里找到它,所以它然后检查全局并且也没有在那里找到它。实际上,您可以通过将 main 中的代码移动到全局命名空间来测试它,它应该可以在那里工作。
  • @BrunoLemos 至于几何问题,以这个例子为例。如果我决定在某些东西上使用pack(),然后尝试使用您的框架类,它将导致代码出错。在这个特定的示例中,它现在并没有受到伤害,但它的不良做法可能会导致您在路上出错。
  • " 会在一个类中构建这一切。"我的想法是让它可读......容易找到和组织的东西......不是吗?大多数代码和程序是一个很棒的单例文件吗?我对花哨的组织有一个错误的概念?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多