在 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()
希望有人觉得这有用!
最初我是按功能编写这个 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()
希望有人觉得这有用!