如何防止 Tkinter 中的全局变量?

How to prevent global variables in Tkinter?

如题所述,如何防止在Tkinter中使用全局变量?我已经开始学习 Tkinter,并且 运行 在我的几乎所有项目中都遇到了问题。我 运行 遇到的问题是大多数 Widget 需要相互交互,从而产生大量依赖关系。下面是我的一个项目中存在此问题的代码。我包含了这个项目的所有代码,因为问题出现在整个代码中。

例如考虑 apply_filter 函数。为了接收来自用户的输入,Apply Filter 按钮的命令功能需要访问输入字段。解决这个问题的一种方法是将所有输入字段作为参数传递给命令函数。但是,我不喜欢这个选项,因为这意味着我必须将所有代码放在一个巨大的块中,使代码更难以阅读,或者我必须通过多个函数传递它,从而导致相同的结果。我在这里选择的选项是使输入成为全局输入,这样我就可以从我的代码中的任何地方访问它们。至少代码更容易阅读。当然这可能不是一个好的解决方案。当 GUI 扩展时,这将产生大量依赖项,很容易导致错误。

长话短说,我想知道:有没有更好的方法来处理这些依赖关系,这样我就不需要创建大量的全局变量或创建不可读的代码? 在此先感谢您付出的努力。

import tkinter as tk
from tkinter import filedialog as fd
import pandas as pd
import numpy as np
import sys

start_filter_row = 0
start_filter_column = 0
data_location = ""

df = None
root = None

filterr = {"customercode":{"column name": "Customer (code)", "value": None, "row_number": start_filter_row},
           "partnr":{"column name": "Part nr", "value": None, "row_number": start_filter_row + 1},
           "partclass":{"column name": "Part class", "value": None, "row_number": start_filter_row + 2},
           "partfamily":{"column name": "Part familiy", "value": None, "row_number": start_filter_row + 3},
           "startdate":{"column name": "Transaction date", "value": None, "row_number": start_filter_row + 4},
           "enddate":{"column name": "Transaction date", "value": None, "row_number": start_filter_row + 5}
           }

inputs = dict()

'''
Load Data
'''

def load_dataset():
    global df
    root.update()
    database_location = fd.askopenfilename()
    df = load_data(database_location)

def load_data(database_location):
    try:
        df = pd.read_pickle(database_location)
        return df
    except Exception as e:
        print("Data location not set!", e)
        root.destroy()
        sys.exit()
        
'''
create Widgets
'''

def create_filter_inputs():
    for key, value in filterr.items():
        label = tk.Label(root, text = key)
        label.grid(row = value["row_number"], column = start_filter_column, sticky = "w")
        
        entry = tk.Entry(root)
        entry.focus_set()
        entry.grid(row = value["row_number"], column = start_filter_column + 1, sticky = "w")
        inputs[key] = entry
        
def create_filter_buttons():
    apply_button = tk.Button(root, text = "Apply Filter", command = apply_filter)
    apply_button.grid(row = start_filter_row + len(filterr), column = 0, sticky = "news")
    
    clear_button = tk.Button(root, text = "Clear Filter", command = clear_filter)
    clear_button.grid(row = start_filter_row + len(filterr), column = 1, sticky = "news")   
    
'''
Button functions
'''

def clear_filter():
    for key, entry in inputs.items():
        entry.delete(0, 'end')
    apply_filter()

def apply_filter():
    for key, entry in inputs.items():
        filterr[key]["value"] = entry.get().split(";")

def main():
    global data_location, root
    
    '''
    Setting up Tkinter Frame and loading dataset
    '''
    
    root = tk.Tk()
    root.title("Data Tool V0.1")
    
    loading_label = tk.Label(root, text = "Loading...", width = 30, height = 5)
    loading_label.pack()
    
    load_dataset()
    
    loading_label.destroy()
    
    n_rows, n_cols = (4, 3)
    
    root.columnconfigure(tuple(range(n_cols)), weight=1)
    root.rowconfigure(tuple(range(n_rows)), weight=1)
    
    '''
    Setting up GUI
    '''
    
    create_filter_inputs()
    create_filter_buttons()
    
    root.mainloop()
    

if __name__ == "__main__":
    main()

您可以通过将 GUI 转换为 class 格式并将它们设为 class 变量来避免使用全局变量。

class GUI:
    def __init__():
        .....
        self.myvariable = ...
    def function():
        newvar = self.myvariable - 5

同样值得注意的是,在函数外部定义的变量可以在函数内部看到,但反之则不行:

>>> def f(a):
...     print(a)
...
>>> b=2
>>> f(b)
2