在 tkinter 中的 类 之间传递 values/tkinter 元素

Passing values/tkinter elements between classes in tkinter

最初我是按功能编写这个 tkinter 应用程序的,但现在由于它变得臃肿,我正在将它转换为 OOP,我遇到的主要问题是理解一种在大量应用程序之间传递变量的简化方法类.

下面是我的代码开头的最低测试版本,在 Mainframe 中定义了两个变量,我想先传递给 FileSelect 以更新它们,然后传递给 LoadFiles.对我来说最大的困惑是为什么 file_list 在 运行 print_files 时似乎正确更新,但是 import_state 变量我想用来启用 [=15] 中的按钮=] 没有。

import os
import tkinter as tk
from tkinter import filedialog


class MainFrame:

    def __init__(self, master):
        self.master = master

        # Variables
        self.file_list = []  # Files list
        self.import_state = tk.DISABLED  # Enable import on correct fp

        # Class Frames
        FileSelect(master, self.file_list, self.import_state)
        LoadFiles(master, self.file_list, self.import_state)


class FileSelect:

    def __init__(self, master, files, button_state):
        self.files = files
        self.button_state = button_state

        # Frame
        self.frame = tk.LabelFrame(master, text='File Selection')
        self.frame.grid(row=0, column=0)

        # Select directory button
        tk.Button(self.frame, text='Open:', command=self.directory_path).grid(row=0, column=0)

        # Tkinter Elements...

    # Directory Selection
    def directory_path(self):

        # Select filepath
        directory = filedialog.askdirectory(initialdir="/", title="Select a directory")
        os.chdir(directory)

        # Populate list of files
        for tb in os.listdir(directory):
            self.files.append(tb)

        # Update GUI, activate button in different class if condition met
        if len(os.listdir(directory)) == 0:
            # Update GUI Labels...
            self.button_state = tk.DISABLED
            print(self.files, self.button_state)
        elif len(self.files) == len(os.listdir(directory)):
            # Update GUI Labels...
            self.button_state = tk.NORMAL
            print(self.files, self.button_state)


class LoadFiles:
    def __init__(self, master, files, button_state):
        self.files = files
        self.button_state = button_state

        # Frame
        self.frame = tk.LabelFrame(master, text='File loading')
        self.frame.grid(row=1, column=0)
        # Load button
        self.import_files_button = tk.Button(self.frame, text='Import TB', command=self.print_files)
        self.import_files_button.grid(row=0, column=0, sticky="EW")

        # Tkinter Elements...

    def print_files(self):
        print(self.files, self.button_state)


if __name__ == "__main__":
    root = tk.Tk()
    MainFrame(root)
    root.mainloop()

除了 类 之间的变量传递问题之外,是否有更简化的一般方法?我看到 OOP 提倡的主要原因之一是它在多大程度上提高了可读性、组织性和隔离 tkinter 元素,但变量处理似乎是从功能转换时的主要关键。

不是传递单个变量,而是传递拥有这些变量的 class 的实例。这减少了你必须来回传递的东西的数量,并且它使代码更加自我记录,因为很明显 self.main.files.append(...) 附加到由主程序管理的列表而不是本地管理的列表。

class MainFrame:
    def __init__(self, master):
        ...
        FileSelect(master, main=self)
        LoadFiles(master, main=self)

class FileSelect:
    def __init__(self, master, main):
        self.main = main
        ...

    # Directory Selection
    def directory_path(self):

        # Select filepath
        directory = filedialog.askdirectory(initialdir="/", title="Select a directory")
        os.chdir(directory)

        # Populate list of files
        for tb in os.listdir(directory):
            self.main.files.append(tb)

        # Update GUI, activate button in different class if condition met
        if len(os.listdir(directory)) == 0:
            # Update GUI Labels...
            self.main.button_state = tk.DISABLED
            print(self.main.files, self.main.button_state)
        elif len(self.files) == len(os.listdir(directory)):
            # Update GUI Labels...
            self.main.button_state = tk.NORMAL
            print(self.main.files, self.main.button_state)

为了跟进,Bryan 和 Martineau 的回答帮助解决了我的问题,但为了其他人可能在处理 tkinter 小部件更新方面遇到问题,我在下面包含了自 [=11 以来的更新代码=] 是一种明确解决 类 之间按钮状态变化的方法,而我理解这一点的主要问题之一是缺乏清晰的最小化示例:

import os
import tkinter as tk
from tkinter import filedialog


class MainFrame:
    def __init__(self, master):
        self.file_selection = FileSelect(master, main=self)
        self.file_load = LoadFiles(master, main=self)


class FileSelect:
    def __init__(self, master, main):
        self.main = main
        self.files = []

        # Frame
        self.frame = tk.LabelFrame(master, text='File Selection')
        self.frame.grid(row=0, column=0)

        # Select directory button
        tk.Button(self.frame, text='Open:', command=self.directory_path).grid(row=0, column=0)

    # Directory Selection
    def directory_path(self):

        # Select filepath
        directory = filedialog.askdirectory(initialdir="/", title="Select a directory")
        os.chdir(directory)

        # Populate list of files
        for tb in os.listdir(directory):
            self.files.append(tb)

        # Update GUI, activate button in different class if condition met
        if len(os.listdir(directory)) == 0:
            self.main.file_load.import_files_button['state'] = tk.DISABLED

        else:
            self.main.file_load.import_files_button['state'] = tk.NORMAL


class LoadFiles:
    def __init__(self, master, main):
        self.main = main

        # Frame
        self.frame = tk.LabelFrame(master, text='File loading')
        self.frame.grid(row=1, column=0)
        # Load button
        self.import_files_button = tk.Button(self.frame, text='Import TB', command=self.print_files,
                                             state=tk.DISABLED)
        self.import_files_button.grid(row=0, column=0, sticky="EW")

        # Tkinter Elements...

    def print_files(self):
        print(self.main.file_selection.files)


if __name__ == "__main__":
    root = tk.Tk()
    MainFrame(root)
    root.mainloop()

希望有人觉得这有用!