[英]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.