【发布时间】:2021-04-21 12:46:51
【问题描述】:
我有一个生成以下表单的模块(使用 Python Tkinter):
如您所见,表单可能具有三种状态:
- 不可编辑 - 输入框被禁用 - 取消和编辑按钮处于活动状态
- 无需更改即可编辑 - 输入框处于活动状态,取消按钮和 编辑按钮变为禁用的保存按钮,并且
- 可通过更改进行编辑 - 输入框处于活动状态,取消按钮变为恢复按钮,保存按钮变为活动状态
我用来实现这个的代码如下:
def display_selected_user(event, user_frame, editable):
def fill_entry_boxes():
# Clear entry boxes
f_name.entry.delete(0, 'end')
l_name.entry.delete(0, 'end')
email.entry.delete(0, 'end')
# Populate with original data
f_name.entry.insert(0, user_dict[user_id]['f_name'])
l_name.entry.insert(0, user_dict[user_id]['l_name'])
email.entry.insert(0, user_dict[user_id]['email'])
cancel_btn.config(text="Cancel")
def cancel_revert_process():
if not changes_made():
user_detail_frame.grid_forget()
close_btn.grid(row=2, column=2, padx=10, pady=10, sticky='E')
else:
MsgBox = messagebox.askquestion('Revert Changes',
f'Changes have been made - are you sure you want to revert?',
icon='question')
if MsgBox == 'yes':
fill_entry_boxes()
edit_save_btn.config(state='disabled', bg='gray80')
def save_or_edit(event, _editable):
if _editable:
save_process(_editable)
else:
make_editable_process(_editable)
def save_process(_editable):
# Notify user of process commencement
user_frame_messenger = MessageBox(user_frame, "")
user_frame_messenger.grid(row=3, column=0, columnspan=3, sticky='nsew')
user_frame_messenger.update_content(user_frame, "Saving user changes to database - one moment")
# Save Process
changes = record_changes()
client = MongoClient('mongodb+srv://xxxxxx.zzyri.mongodb.net/test?')
db = client['football_data']
collection = db['users']
for key in changes[1]:
collection.update_one({"_id": ObjectId(changes[0])},
{"$set": {key: changes[1][key]}}
)
# Notify user of process completion
user_frame_messenger.destroy()
messagebox.showinfo("User detail updated",
"The changes to the user details have been saved")
user_frame.grid_forget()
cancel_revert_process()
_editable = False
def make_editable_process(_editable):
f_name.entry.config(state='normal')
l_name.entry.config(state='normal')
email.entry.config(state='normal')
_editable = True
edit_save_btn.config(text="Save", state='disabled', bg='gray80')
def key_pressed(event):
if changes_made():
cancel_btn.config(text="Revert")
edit_save_btn.config(state='normal', bg="#43E082")
else:
cancel_btn.config(text="Cancel")
edit_save_btn.config(state='disabled', bg='gray80')
# Record data of selected user
user = user_lst.tree.focus()
user_data = user_lst.tree.item(user)
user_id = user_data['values'][0]
# Create objects
f_name = LabelEntryCombo(user_frame, "First name:")
l_name = LabelEntryCombo(user_frame, "Last name:")
email = LabelEntryCombo(user_frame, "Email:")
cancel_btn = ColourSchemedButton(user_frame, "PaleGreen", "Cancel")
edit_save_btn = ColourSchemedButton(user_frame, "GreenBlue", "Edit", state='normal')
# Fill entry boxes
fill_entry_boxes()
# Bind objects
f_name.entry.bind('<KeyRelease>', lambda e: key_pressed(e))
l_name.entry.bind('<KeyRelease>', lambda e: key_pressed(e))
email.entry.bind('<KeyRelease>', lambda e: key_pressed(e))
cancel_btn.config(command=cancel_revert_process)
edit_save_btn.config(command=lambda e=event, d=editable: save_or_edit(e, d))
# Place and removal of objects
close_btn.grid_forget()
user_detail_frame.grid(row=2, columnspan=3, padx=10, pady=10, sticky='NW')
f_name.frame.grid(row=0, columnspan=3, pady=10, padx=10)
l_name.frame.grid(row=1, columnspan=3, pady=10, padx=10)
email.frame.grid(row=2, columnspan=3, pady=10, padx=10)
cancel_btn.grid(row=3, column=1, pady=10, padx=10)
edit_save_btn.grid(row=3, column=2, pady=10, padx=10)
# Configure grid
user_detail_frame.grid_columnconfigure(0, weight=1)
user_detail_frame.grid_columnconfigure(1, weight=0)
user_detail_frame.grid_columnconfigure(2, weight=0)
# Set state of objects
f_name.entry.config(state='disabled')
l_name.entry.config(state='disabled')
email.entry.config(state='disabled')
如您所知 - 我使用 lambda 函数将 save_edit_btn 与以下配置绑定,该函数传递用作状态处理程序的 editable 变量 edit_save_btn.config(command=lambda e=event, d=editable: save_or_edit(e, d))
editable 变量在此函数外部初始化为 False,并传递给最顶部的函数 display_selected_user()(如果您愿意,是主程序的回调函数)。因此,当按下save_edit_btn 时,该函数使条目处于活动状态并相应地更改其他小部件(根据函数make_editable_process())并将editable 变量更改为True(即使在它被初始化的主程序中)
问题是,之后该过程返回到 lambda 行并将 editable 变量重置为 False - 我不明白为什么 - 因此永远无法初始化 save_process()。
任何关于为什么会这样的想法将不胜感激 - 如果您需要更多代码或详细信息,请告诉我。
【问题讨论】:
-
这里有很多无法运行的代码供我们查看,但
_editable不是global的意思,它的值只会在函数内部相同。因此,除非您将更改后的值传递给新函数,否则该值应该被视为函数内部已经存在的值。或使用global _editable。 -
您对局部变量所做的任何更改,例如
make_editable_process中的_editable,仅在该函数内部可见,因此请在外部看到更改,您需要返回它,保存到一些外部给给定可变对象的函数(例如那些各种按钮的东西),或将其声明为global或nonlocal -
(1)
_editable是局部变量,它不会改变外部变量——即使同名。 (2) 对于像True/False、数字、字符串这样的值,它会将其值发送给函数(或其他变量)——而不是对变量的引用——所以a = False、_editable = a、_editable = True、print(a)和a仍然是False,而不是True。为此,您必须使用 ietkinter.BooleanVar()。a = tk.BooleanVar(value=False)、_editable = a、_editable.set(True)、print(a.get())