[英]How to make a Tkinter Button change its own text attribute?
上下文:这是我正在制作的程序的一部分,该程序使用 Tkinter 构建一个表单,该表单尊重特定的 json 模式。
它以递归方式工作,并且每次在模式中遇到“对象”类型(实际上对应于 python 中的 dict 类型)时都会调用 build_dict_form。 build_rec_form 将调用另一个 function 来完成表单的该部分。
def build_dict_form(schema, master):
answers = {}
def btn_k_cmd_factory(k, k_properties, k_frame):
def res():
if k in answers:
del answers[k]
#TODO: delete subframe of k_frame
else:
answers[k] = build_rec_form(k_properties, k_frame)
# btn_k.text = "Cancel"
return res
properties = schema["properties"]
if "maxProperties" not in schema:
for k in properties:
frm_k = tk.Frame(master=master, bd=4, highlightbackground="red", highlightthickness=0.5)
lbl_k = tk.Label(master=frm_k, text=k)
lbl_k.pack()
answers[k] = build_rec_form(properties[k], frm_k)
frm_k.pack()
else:
for k in properties:
frm_k = tk.Frame(master=master, bd=4, highlightbackground="red", highlightthickness=0.5)
lbl_k = tk.Label(master=frm_k, text=k)
btn_k = tk.Button(master=frm_k, text="choose", command=btn_k_cmd_factory(k, properties[k], frm_k))
lbl_k.pack()
btn_k.pack()
frm_k.pack()
return answers
我现在的问题是,当我点击 btn_k 时,它的文本属性更改为“取消”(TODO 不是这个问题的一部分)。
btn_k.text = "Cancel"
行,因为在 btn_k_cmd_factory 内部我无权访问 btn_k object。我怎样才能使它工作?
编辑:如果你需要运行,你可以使用:
import tkinter as tk
import jsonschema
type_conversion = {
"object": dict,
"integer": int,
"string": str,
"array": list
}
def deep_eval(structure):
t = type(structure)
if t == dict:
return {k: deep_eval(structure[k]) for k in structure}
if t == list:
return [deep_eval(k) for k in structure]
else:
return structure()
def ask_new_item(schema):
res = {}
validated = {}
def validate():
nonlocal validated
validated = deep_eval(res)
try:
jsonschema.validate(instance=validated, schema=schema)
window.destroy()
except jsonschema.exceptions.ValidationError as e:
print("schema not validated:")
print(e)
window = tk.Tk()
btn_close = tk.Button(master=window, text="Validate", command=validate)#TODO: ["state"]=tk.DISABLED
res = build_rec_form(schema, window)
btn_close.pack()
window.mainloop()
return validated
def build_rec_form(schema, master):
frm_subform = tk.Frame(master=master, bd=4, highlightbackground="black", highlightthickness=0.5)
helper_text = f"{schema.get('description', '<no description>')}, of type {schema['type']}"
lbl_helper = tk.Label(master=frm_subform, text=helper_text)
lbl_helper.pack()
t_python = type_conversion[schema["type"]]
res_method = None
if t_python == str or t_python == int:
untyped_method =build_str_form(schema, frm_subform)
def res_method(): return t_python(untyped_method())
elif t_python == dict:
res_method = build_dict_form(schema, frm_subform)
elif t_python == list:
res_method = build_list_form(schema, frm_subform)
else:
print(f"type not supported: {t_python}")
frm_subform.pack()
return res_method
def build_dict_form(schema, master):
answers = {}
def btn_k_cmd_factory(k, k_properties, k_frame):
def res():
if k in answers:
del answers[k]
#TODO: delete subframe of k_frame
else:
answers[k] = build_rec_form(k_properties, k_frame)
# btn_k.text = "Cancel"
return res
properties = schema["properties"]
if "maxProperties" not in schema:
for k in properties:
frm_k = tk.Frame(master=master, bd=4, highlightbackground="red", highlightthickness=0.5)
lbl_k = tk.Label(master=frm_k, text=k)
lbl_k.pack()
answers[k] = build_rec_form(properties[k], frm_k)
frm_k.pack()
else:
for k in properties:
frm_k = tk.Frame(master=master, bd=4, highlightbackground="red", highlightthickness=0.5)
lbl_k = tk.Label(master=frm_k, text=k)
btn_k = tk.Button(master=frm_k, text="choose", command=btn_k_cmd_factory(k, properties[k], frm_k))
lbl_k.pack()
btn_k.pack()
frm_k.pack()
return answers
def build_list_form(schema, master):
#TODO
def res():
return []
return res
def build_str_form(schema, master):
ent_answer = tk.Entry(master=master)
ent_answer.pack()
return ent_answer.get
if __name__ == "__main__":
schema = {
"type": "object",
"properties": {
"Prop1": {
"type": "string"
},
"Prop2": {
"type": "integer"
}
}
"maxProperties": 1
}
print(ask_new_item(schema))
您可以使用config
或configure
编辑文本:
btn_k.text.config(text='Cancel')
您也可以使用属性索引:
btn_k['text'] = 'Cancel'
“出于某种原因,我不明白我不能在没有命令属性的情况下创建按钮并在之后更改它。” 〜你可以,类似于上面:
btn_k['command'] = new_func
编辑:进一步探讨问题,只有在触发else
时才会创建按钮,因此您可能需要预定义 function 顶部的按钮:
def build_dict_form(schema, master):
answers = {}
btn_k = None
def btn_k_cmd_factory(k, k_properties, k_frame):
def res():
if k in answers:
del answers[k]
#TODO: delete subframe of k_frame
else:
answers[k] = build_rec_form(k_properties, k_frame)
if btn_k is not None:
btn_k['text'] = 'Cancel'
return res
编辑 2:传入参数,稍后更改文本怎么样? 结合以上提示:
def build_dict_form(....):
def btn_k_cmd_factory(k, k_properties, k_frame, btn_k):
....
else:
answers[k] = build_rec_form(k_properties, k_frame)
btn_k['text'] = 'Cancel'
....
else:
....
btn_k = tk.Button(master=frm_k, text="choose")
btn_k['command'] = btn_k_cmd_factory(k, properties[k], frm_k, btn_k)
首先,“text”和“command”都不是 Button 对象的属性:访问它们需要通过btn['text']
和btn['command']
考虑到这一点,可以在创建按钮后更改按钮的命令:
btn_k = tk.Button(master=frm_k, text="choose")
btn_k['command'] = btn_k_cmd_factory(k, properties[k], frm_k, btn_k)
因此将按钮 object 作为参数用于其自己的命令 function。
基于@CoolCloud 的回答
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.