如何避免动态生成中的全局变量。 tkinter 形式?函数插入的值不会保存,手动输入的值会在代码更改后保存

How to avoid global variables in a dynamically gen. tkinter form? Values inserted by functions won't save, hand typed values will after code change

我正在尝试删除我依赖的全局变量,而不是 passing/returning 必要的值。它似乎部分起作用,但结果让我感到困惑。

有没有办法在不切换到面向对象的情况下避免全局变量?*

使用保存小部件的全局变量,表单可以按预期工作。它创建一个默认的空白表单,并可以使用从文件加载的值重建表单,并保存小部件值,无论这些值是输入的、从文件加载的、加载后编辑的,等等。

但是,当我尝试 pass/return 小部件列表而不是使用全局变量时,仅保存手动输入的值,一旦调用 load_file 函数,任何对 save_file 只是保存最后手动输入的值。 (要查看差异,切换当前注释,标记为内联注释的行缺少注释)。

我想帮助您了解这里的问题,以及正确执行此操作的选项。

import tkinter as tk

root = tk.Tk()
root.geometry('900x800')

form_frame = tk.Frame(root) 
button_frame = tk.Frame(root)

form_frame.grid(row = 0)
button_frame.grid(row = 1)

# default form, or form that matches opened dataset 
def build_form(dataset = None): 
    global entry_objects        #<==== Comment out this line (1/4)...
    entry_objects = []
    if dataset == None:            
        rowcount = 2   
    else:
        rowcount = len(dataset)      
    for row_i in range(rowcount):
        entry_list = []
        if dataset is not None:
            data_row = dataset[row_i]     
        for col_i in range(3):   
            entry = tk.Entry(form_frame)
            if dataset is not None:
                entry.insert(0, str(data_row[col_i]))
            entry_list.append(entry)
            entry.grid(row = row_i, column = col_i)    
        entry_objects.append(entry_list)
    #return(entry_objects)      #<==== ... uncomment this line (2/4)...

def open_file():    # open_file(), save_file() are just substitutes.
    test_data = [['a1', 'a2', 'a3'],['b1', 'b2', 'b3'],['c1', 'c2', 'c3']]
    build_form(test_data)

def save_file(entry_objects):
    entry_values =  [[j.get() for j in i]  for i in entry_objects]
    print('--> Saved to csv file: ')
    print(entry_values)

build_form()                    #<==== ... comment this line (3/4)...   
#entry_objects = build_form()   #<==== ... and uncomment this line (4/4).   


open_button = tk.Button(button_frame, text = 'Load Test Data',
                     command = open_file)
save_button = tk.Button(button_frame, text = 'Save', 
                     command = lambda: save_file(entry_objects))
exit_button = tk.Button(button_frame, 
                     text = 'Exit', command=root.quit)

open_button.pack(side = 'left')
save_button.pack(side = 'left')
exit_button.pack(side = 'left')

root.mainloop()

这是我的第一个程序中有问题的部分,为了清晰起见进行了很多修剪和简化。

*在学习 OOP 之前,我想澄清我在程序方面的困惑。在阅读它导致的问题之前,我使用了一个全局变量,并且理解如何避免使用全局变量一直是一个挑战。

有很多关于从动态生成的小部件访问值、避免全局变量等的问题让我走到这一步,但 none 我理解为解决这个问题。

据我所知,这就是我能说的。

代码是什么(global entry_objects 没有注释),一切就OK了。当 save_file 函数 运行s 时, entry_objects 变量被设置为更新后的值并给出正确的数据。

当 build_form 函数是 运行 和 return 语句时,open_file 函数不会更新为将 build_file 作为值,相反,它希望它是一个声明。

def open_file():    # this, save_file are just substitutes.
    test_data = [['a1', 'a2', 'a3'],['b1', 'b2', 'b3'],['c1', 'c2', 'c3']]
    build_form(test_data)    # this does nothing

它应该需要包含全局语句(因为它在函数外更改值)global entry_objects并且需要将 entry_objects 设置为 build_form 函数给出的值, 意思是 entry_objects = build_form(test_data)。更新后的函数如下所示:

# updated open_file for when build_form returns a value rather than changing the value by itself
def open_file():
    # this makes changes to entry_objects visible to things outside the function
    global entry_objects
    test_data = [['a1', 'a2', 'a3'],['b1', 'b2', 'b3'],['c1', 'c2', 'c3']]
    entry_objects = build_form(test_data)    # this sets the returned value to entry_objects

基本上我要说的(在这一大堆乱七八糟的词中)是 entry_objects 将必须更改,这是进行更改并将更新后的值投射到所有其他调用的唯一方法变量是使用 global 并使对 entry_objects 的所有更改对其他所有内容可见,包括

save_btn = tk.Button(
    button_frame, text='Save',
    command=lambda: save_file(entry_objects)
).pack(side='left')

最后。

只是一个小提示,尝试将您的行换行到 74 个字符,因为它可以帮助使用小屏幕的其他人看到整个图片,而不是四处滚动:)

如果我不清楚,请随时告诉我我需要进一步解释的内容。在那个表格上也做得很好 :D