菜單是GUI程式的常用控件之一,本文說明Tkinter中如何使用菜單。還是先看示例視訊:
視訊中的小程式是在之前的Text控件示例程式的基礎上修改而成的,功能基本一緻,隻是增加了菜單操作的功能。讀者可以稍微注意一下Enable/Disable按鈕和菜單項的關聯情況。
首先是建構主菜單對象。代碼一共分兩步:一是以主視窗為參數建構一個菜單對象top_menu,二是用top_menu對象設定主視窗對象的menu屬性。
需要注意的是,這裡沒有使用pack,grid等布局方法。
top_menu = Menu(root)root.config(menu=top_menu)
接下來的代碼為主菜單增加編輯(edit)和格式(format)兩個下級菜單。
建構下級菜單也分兩步:建構對象并添加到主菜單上。使用的參數應該基本不需要解釋,tearoff除外。如果不設定tearoff為False的話,下級菜單的最上面會出現一條橫線。代碼中故意為edit_menu指定tearoff為False而format菜單使用預設值,結果可以在菜單表示時看到。
edit_menu = Menu(top_menu, tearoff=False)top_menu.add_cascade(label='Edit', menu=edit_menu)format_menu = Menu(top_menu)top_menu.add_cascade(label='Format', menu=format_menu)
接下來的代碼稍長,其中有一部分是之前示例代碼的内容,讀者隻要注意菜單相關的部分就好。
text_enable = IntVar()text_enable.set(1)
# change state function.def enable_text(): text_enable.set(1)
# change state button.eb = Radiobutton(root,text="Enable", width=8, command=enable_text, value=1, variable=text_enable)eb.grid(row=1, column=0, sticky=E+W)edit_menu.add_radiobutton(label='Enable', command=enable_text, value=1, variable=text_enable)
# change state function.def disable_text(): text_enable.set(0)
# change state button.eb = Radiobutton(root,text="Disable", width=8, command=disable_text, value=0, variable=text_enable)eb.grid(row=1, column=1, sticky=E+W)edit_menu.add_radiobutton(label='Disable', command=disable_text, value=0, variable=text_enable)
代碼首先建構一個text_enable變量,然後在按鈕或者菜單操作時修改這個變量的值。同時在增加readiobutton菜單項時指定觀察對象變量(variable)和顯示為選中狀态所需的變量值(value)。這種方式和Rediobutton控件的用法完全相同。
接下來我們希望修改Text控件的有效狀态,這可以通過在上述代碼中的enable_text/disable_text方法中增加修改Text控件的有效狀态來實作,也可以采用下面的方法,即監視變量的狀态變化:
def var_changed(*args): if text_enable.get(): text.config(state='normal') text.config(background='#a0ffa0') else: text.config(state='disabled') text.config(background='#efefef')# set variable observer.text_enable.trace_variable('w', var_changed)
接下來是建構其他的普通菜單項的過程,讀者可以結合按鈕的代碼來了解。形式稍有差別,内容完全相同。
# delete selection.def delete_selection(): try: sel_from = text.index(SEL_FIRST) sel_to = text.index(SEL_LAST) # delete the selection. text.delete(sel_from, sel_to) except TclError: pass
# delete selection button.db = Button(root,text="Delete", width = 8, command=delete_selection)db.grid(row=1, column=2, sticky=E+W)edit_menu.add_radiobutton(label='Delete', command=delete_selection)
# undo buttonundo = Button(root, text='Undo', width = 8, command=lambda:text.edit_undo())undo.grid(row=1, column = 3, sticky=E+W)edit_menu.add_radiobutton(label='Undo', command=lambda:text.edit_undo())
#redo buttonredo = Button(root, text='Redo', width = 8, command=lambda:text.edit_redo())redo.grid(row=1, column = 4, sticky=E+W)edit_menu.add_radiobutton(label='Redo', command=lambda:text.edit_redo())
# create fontsfonts = [ Font(family='SimHei', size=20, weight=BOLD), Font(family='SimHei', size=16), Font(family='SimSun', size=12, weight=BOLD), Font(family='SimSun', size=12) ]
# delete selection.def format(index): tag_name = 'Format' + str(index) try: sel_from = text.index(SEL_FIRST) sel_to = text.index(SEL_LAST) for name in text.tag_names(): text.tag_remove(name, sel_from, sel_to) text.tag_add(tag_name, sel_from, sel_to) # set format at first time. range_count = len(text.tag_ranges(tag_name)) if range_count == 2: text.tag_config(tag_name, font=fonts[index]) except TclError: pass
# delete selection button.for i in range(0, 4): fb = Button(root, text="Format" + str(i), width = 8, command=lambda v=i : format(v)) format_menu.add_command(label="Format" + str(i), command=lambda v=i : format(v)) fb.grid(row=2, column=i, sticky=E+W)
# create text widget.text = Text(root, undo=True, background="#a0ffa0", foreground="#000000", height = 10)text.grid(row=3 , column=0, columnspan=8)
完整代碼可以從下面的連結下載下傳:
https://github.com/xueweiguo/TkinterPrimer/blob/master/Sample/20%20.py