Tkinter库的学习记录16-菜单Menu和工具栏Toolbars

16、菜单Menu和工具栏Toolbars

16-1 菜单Menu设计的基本概念

窗口中一般会由菜单设计,菜单是一种下拉式窗体,在这种窗体中可以设计菜单列表,建立菜单的方法是Menu(),它的语法格式如下。

Menu(父对象, options, ...)

参数一:同上

options参数:

(1) activebackground:当光标移至此菜单列表上时的背景颜色。

(2) activeborderwidth:当被鼠标选取时它的外边框厚度,默认是1.

(3) activeforeground:当光标移至此菜单列表上时的前景色彩。

(4) bd:所有菜单列表的外边框厚度,默认是1

(5) bg:菜单列表未被选取时的背景色彩。

(6) cursor:当菜单分离时,鼠标光标在列表上的外观。

(7) disabledforeground:菜单列表是DISABLED时的颜色。

(8) font:菜单列表文字的字形

(9) fg:菜单列表未被选取时的前景色彩。

(10) image:菜单的图标。

(11) tearoff:菜单上方的分隔线,这是一个虚线线条,有分隔线时tearoff为True或1,此时菜单列表从位置1开始放置,同时可以让菜单分离,分离方式是开启菜单后单击分隔线。如果将tearoff设为False或0时,此时不会显示分隔线,也就是菜单无法分离,但是菜单列表将从位置0开始存放。相关实例可以参考16-2节。

下列是其它相关的方法。

(1) add_cascade():建立分层菜单,同时让此子功能列表与父菜单建立链接。

(2) add_command():增加菜单列表。

(3) add_separator():增加菜单列表的分隔线,可以参考16-3节。

下面程序实例ch16_1:建立最上层的菜单列表,单击"Hello!"会出现“欢迎使用菜单”的对话框,单击“Exit!”则程序结束。

from tkinter import * from tkinter import messagebox def hello(): messagebox.showinfo("Hello", "欢迎使用菜单") root = Tk() root.title("ch16_1") root.geometry("300x100") # 建立最上层菜单 menubar = Menu(root) menubar.add_command(label="Hello!", command=hello) menubar.add_command(label="Exit!", command=root.destroy) root.config(menu=menubar) # 显示菜单对象 root.mainloop()

执行结果

上述的设计理念是第12行先建立menubar对象,然后第13、14行分别将Hello!和Exit!命令列表建立在menubar上。

上述程序虽然可以执行,但这并不是一个正规的菜单设计方式,正规菜单是在最上方先建立菜单类别,然后才在各菜单类别内建立相关子菜单列表,这些子菜单列表适用下拉式窗体显示。

程序实例ch16_2:建立一个File菜单,然后在此菜单内建立下拉式列表命令。

from tkinter import * from tkinter import messagebox def newFile(): messagebox.showinfo("New File", "开新档案") root = Tk() root.title("ch16_2") root.geometry("300x100") # 建立最上层菜单 menubar = Menu(root) # 建立菜单类别对象,并将此菜单类别命名为File filemenu = Menu(menubar) menubar.add_cascade(label="File", menu=filemenu) # 在file菜单内建立菜单列表 filemenu.add_command(label="NewFile", command=newFile) filemenu.add_command(label="Exit!", command=root.destroy) root.config(menu=menubar) # 显示菜单对象 root.mainloop()

执行结果

上述建立File菜单的关键是14、15行,filemenu则是File菜单的对象,第17、18行是使用filemenu对象在FIle菜单内建立New FIle和Exit!命令列表。

16-2 tearoff参数

在16-1节的Menu()方法的参数options中,介绍了tearoff参数,它的默认值是1,至于其它细节可以参考该部分的说明,由于这是默认值,所以若是开启菜单时可以看到“tearoff=1”参数产生的虚线分隔线。

若单击虚线,可以让这个下拉菜单分离,结果如上方右图所示。

下面程序实例ch16_3,在第14行建立菜单时设置“tearoff=False”,重新设计ch16_2,然后观察执行结果,可以发现此虚线已被取消,这也造成无法将此下拉菜单从ch16_3的窗口中分离。

from tkinter import * from tkinter import messagebox def newFile(): messagebox.showinfo("New File", "开新档案") root = Tk() root.title("ch16_3") root.geometry("300x100") # 建立最上层菜单 menubar = Menu(root) # 建立菜单类别对象,并将此菜单类别命名为File filemenu = Menu(menubar, tearoff=False) menubar.add_cascade(label="File", menu=filemenu) # 在file菜单内建立菜单列表 filemenu.add_command(label="NewFile", command=newFile) filemenu.add_command(label="Exit!", command=root.destroy) root.config(menu=menubar) # 显示菜单对象 root.mainloop()

执行结果 参考下图虚线被隐藏了。

16-3 菜单列表间加上分隔线

在建立下拉菜单列表时,如果列表项目有很多,可以适当地使用add_separator()方法在菜单列表内加上分隔线。

下面程序实例ch16_4:扩充设计ch16_2,在File菜单内建立5个指令列表,同时适时地在指令列表间建立分隔线,可以参考第24行和27行。

from tkinter import * from tkinter import messagebox def newFile(): messagebox.showinfo("New File", "新建文档") def openFile(): messagebox.showinfo("New File", "打开文档") def saveFile(): messagebox.showinfo("New File", "保存文档") def saveAsFile(): messagebox.showinfo("New File", "另存为") root = Tk() root.title("ch16_4") root.geometry("300x180") menubar = Menu(root) # 建立最上层菜单 # 建立菜单类别对象,并将此菜单类别命名为File filemenu = Menu(menubar, tearoff=False) menubar.add_cascade(label="File", menu=filemenu) # 在file菜单内建立菜单列表 filemenu.add_command(label="New File", command=newFile) filemenu.add_command(label="Open File", command=openFile) filemenu.add_separator() filemenu.add_command(label="Save", command=saveFile) filemenu.add_command(label="Save As", command=saveAsFile) filemenu.add_separator() filemenu.add_command(label="Exit!", command=root.destroy) root.config(menu=menubar) # 显示菜单对象 root.mainloop()

执行结果

16-4 建立多个菜单地应用

一个实用地窗口应用程序在最上层menubar中应该会有多组菜单类别,在先前地实例中只建立了File菜单filemenu对象,所使用的方法如下。

menubar = Menu(root) filemenu = Menu(menubar) menu.add_cascade(label="File", menu=filemenu)

如果想要建立多组菜单类别,所需要的就是增加设计上述第2、3行,然后用不同的名称取代即可。

下面程序实例ch16_5:扩充实例ch16_4,增加Help菜单,在这个菜单内增加About me命令列表。

from tkinter import * from tkinter import messagebox def newFile(): messagebox.showinfo("New File", "新建文档") def openFile(): messagebox.showinfo("New File", "打开文档") def saveFile(): messagebox.showinfo("New File", "保存文档") def saveAsFile(): messagebox.showinfo("New File", "另存为") def aboutMe(): messagebox.showinfo("Help File", "关于我") root = Tk() root.title("ch16_5") root.geometry("300x180") menubar = Menu(root) # 建立最上层菜单 # 建立菜单类别对象,并将此菜单类别命名为File filemenu = Menu(menubar) menubar.add_cascade(label="File", menu=filemenu) # 在file菜单内建立菜单列表 filemenu.add_command(label="New File", command=newFile) filemenu.add_command(label="Open File", command=openFile) filemenu.add_separator() filemenu.add_command(label="Save", command=saveFile) filemenu.add_command(label="Save As", command=saveAsFile) filemenu.add_separator() filemenu.add_command(label="Exit!", command=root.destroy) # 建立菜单类别对象,并将此菜单类别命名为Help helpmenu = Menu(menubar) menubar.add_cascade(label="Help", menu=helpmenu) # 在help菜单内建立菜单列表 helpmenu.add_command(label="About me", command=aboutMe) root.config(menu=menubar) # 显示菜单对象 root.mainloop()

执行结果

16-5 Alt快捷键

快捷键是某个菜单类别或是列表指令的英文字符串内为单一字母增加下划线,然后可以用Alt键先启动此功能,当菜单显示下划线字母时,可以直接按指定字母键启动该功能。设计方式是在下列两个方法内增加underline参数。

add_cascade(..., underline=n) # n代表第n个索引字母含下划线 add_cascade(..., underline=n) # n代表第n个索引字母含下划线

add_cascade()的underline是为菜单类别增加字母下划线,add_command()的underline是为命令列表增加字母下画线,上述索引从0开始计算。当然,在将所选择的字母处理成带有下划线时,必须适度选择具有代表性的字母,通常会是字符串的第一个字母,例如,File菜单可以选择F,Help菜单可以选择H,等等。有时候会发生字符串的第一个字母与先前的字母重复,例如,Save的S与Save As的S,这时第二个出现的字符串可以适当选择其它字母,可参考下列实例。

下面程序实例ch16_6:重新设计ch16_5,为菜单泪飙和列表命令建立快捷键。

from tkinter import * from tkinter import messagebox def newFile(): messagebox.showinfo("New File", "新建文档") def openFile(): messagebox.showinfo("New File", "打开文档") def saveFile(): messagebox.showinfo("New File", "保存文档") def saveAsFile(): messagebox.showinfo("New File", "另存为") def aboutMe(): messagebox.showinfo("Help File", "关于我") root = Tk() root.title("ch16_6") root.geometry("300x180") menubar = Menu(root) # 建立最上层菜单 # 建立菜单类别对象,并将此菜单类别命名为File filemenu = Menu(menubar) menubar.add_cascade(label="File", menu=filemenu, underline=0) # 在file菜单内建立菜单列表 filemenu.add_command(label="New File", command=newFile, underline=0) filemenu.add_command(label="Open File", command=openFile, underline=0) filemenu.add_separator() filemenu.add_command(label="Save", command=saveFile, underline=0) filemenu.add_command(label="Save As", command=saveAsFile, underline=5) filemenu.add_separator() filemenu.add_command(label="Exit!", command=root.destroy, underline=0) # 建立菜单类别对象,并将此菜单类别命名为Help helpmenu = Menu(menubar) menubar.add_cascade(label="Help", menu=helpmenu, underline=0) # 在help菜单内建立菜单列表 helpmenu.add_command(label="About me", command=aboutMe, underline=1) root.config(menu=menubar) # 显示菜单对象 root.mainloop()

执行结果

可以看到File的F和Help的H字母含下划线,按F键可以开启File菜单。

上述左图中按N键,可以执行New File功能。

16-6 Ctrl+快捷键

在设计菜单列表时也可以在指令右边设计Ctrl+X之类的快捷键,X是代表一个快捷键的英文字母,要设计这类操作可以借助accelerator参数,然后再使用第11章所学的bind()方法将此快捷键绑定一个callback()方法。为了使程序简化,可以借助Ctrl+快捷键的方法,下面的ch16_7简化了ch16_6。

下面程序实例ch16_7:设计File菜单的New File子菜单,可以按Ctrl+N组合键。

from tkinter import * from tkinter import messagebox def newFile(): messagebox.showinfo("New File", "新建文档") root = Tk() root.title("ch16_7") root.geometry("300x180") menubar = Menu(root) # 建立最上层菜单 # 建立菜单类别对象,并将此菜单类别命名为File filemenu = Menu(menubar) menubar.add_cascade(label="File", menu=filemenu, underline=0) # 在file菜单内建立菜单列表 filemenu.add_command(label="New File", command=newFile, accelerator="Ctrl+N") filemenu.add_separator() filemenu.add_command(label="Exit!", command=root.destroy, underline=0) root.config(menu=menubar) # 显示菜单对象 root.bind("<Control-N>", lambda event: messagebox.showinfo("New File", "新建文档")) root.mainloop()

执行结果

在上述第21、22行是执行ctrl+N快捷键的绑定,由于所绑定事件会回传event事件给callback()方法,所以无法直接调用第4、5行的newFile()方法,因为newFile()方法没有传递任何参数,碰上这种问题如果凭直觉再建立一个专供此快捷键使用的方法,此例中使用Lambda表达式处理,以简化整个程序的设计。

16-7 建立子菜单

建立菜单时所使用的概念如下。

menubar = Menu(root) filemenu = Menu(menubar) menu.add_cascade(label="File", menu=filemenu)

上述是建立File菜单。所谓的建立子菜单就是在File菜单内另外建立一个子菜单。如果所要建立的子菜单是Find子菜单,所要建的对象是findmenu,此时可以使用下列命令。

findmenu = Menu(filemenu) xxx # 这是建立子菜单列表 xxx # 这是建立子菜单列表 filemenu.add_cascade(label="Find", menu=findmenu)

下面程序实例ch16_8:在File菜单内建立Find子菜单,这个子菜单内有Find Next和Find Pre命令

from tkinter import * from tkinter import messagebox def findNext(): messagebox.showinfo("Fine Next", "查找下一个") def findPre(): messagebox.showinfo("Fine Next", "查找前一个") root = Tk() root.title("ch16_8") root.geometry("300x180") menubar = Menu(root) # 建立最上层菜单 # 建立菜单类别对象,并将此菜单类别命名为File filemenu = Menu(menubar) menubar.add_cascade(label="File", menu=filemenu, underline=0) # 在file菜单内建立菜单列表 # 首先在File菜单内建立Find子菜单对象 findmenu = Menu(filemenu, tearoff=0) # 取消分隔线 findmenu.add_command(label="Find Next", command=findNext) findmenu.add_command(label="Find Pre", command=findPre) filemenu.add_cascade(label="Find", menu=findmenu) # 下面是增加分隔线和建立Exit!子菜单 filemenu.add_separator() # 添加分隔线 filemenu.add_command(label="Exit!", command=root.destroy, underline=0) root.config(menu=menubar) # 显示菜单对象 root.mainloop()

执行结果

由于在子菜单的设计中一般为省略虚线分隔线设计,所以在第19行的menu()方法中增加了tearoff=0.

16-8 建立弹出式菜单

当使用Windows操作系统时,可以在桌面上单击鼠标右键,此时会弹出一个菜单,这就是弹出式菜单Popupmenu,有人将此菜单称为快捷菜单。

设计这类菜单与先前需在窗口的menubar区建立菜单类别有一些差异,建立好Menu对象后,可以直接利用此对象建立指令列表,最后再单击鼠标右键操作绑定显示弹出菜单即可。

popupmenu = Menu(root, tearoff=False) # 隐藏虚线分隔线 popupmenu.add_command(label=" xx", command=" yy") # 建立指令列表 ..., root.bind("<Button-3>", callback) # 绑定单击鼠标右键显示弹出菜单

下面程序实例ch16_9:设计弹出菜单,这个弹出菜单中有两个子菜单,一个是Minimize可以将窗口缩成图标,另一个是Exit结束程序。

from tkinter import * def minimizeIcon(): # 缩小窗口为图标 root.iconify() def showPopupMenu(event): # 显示弹出菜单 popupmenu.post(event.x_root, event.y_root) root = Tk() root.title("ch16_9") root.geometry("300x180") popupmenu = Menu(root, tearoff=False) # 建立弹出菜单对象 # 在弹出菜单内建立两个指令列表 popupmenu.add_command(label="Minimize", command=minimizeIcon) popupmenu.add_command(label="Exit", command=root.destroy) # 单击鼠标右键绑定显示弹出菜单 root.bind("<Button-3>", showPopupMenu) root.mainloop()

执行结果

上述第4行的iconify()是最小化窗口,第7行的post()方法是由popupmenu对象启动,相当于可以在鼠标光标位置(event.x_root, event.y_root)弹出此菜单。

16-9 add_checkbutton()

在设计菜单列表时,也可以将命令用复选框(checkbutton)方式表示,也称为Check menu button,下面将用程序实例讲解。程序实例ch16_10在执行时,在窗口下方可以看到状态栏,View菜单中的Status其实就是用的复选框命令。

上述工作原理是当Status状态为True时,Status左边可以有勾选符号,同时窗口下方会有状态栏,可参考上方左图。当Status状态是False时,左边没有勾选符号,同时窗口下方不会有状态栏,可参考上方右图。Check menu button的工作原理和Widget对象Checkbutton相同,单击可以切换状态是True或False。

下面程序实例ch16_10:设计当Status为True时可以显示状态栏,当Status为False时可以隐藏状态栏,这个程序的状态栏使用标签Label方式处理,可以参考29~32行。

from tkinter import * def status(): if demoStatus.get(): # 设定是否显示状态栏 statusLabel.pack(side=BOTTOM, fill=X) else: statusLabel.pack_forget() # 隐藏标签栏 root = Tk() root.title("ch16_10") root.geometry("300x180") menubar = Menu(root) # 建立最上层菜单 # 建立菜单类别对象,并将此菜单类别命名为File filemenu = Menu(menubar, tearoff=False) menubar.add_cascade(label="File", menu=filemenu) # 在File菜单内建立菜单列表Exit filemenu.add_command(label="Exit", command=root.destroy) # 建立菜单类别对象,并将此菜单类别命名为View viewmenu = Menu(menubar, tearoff=False) menubar.add_cascade(label="View", menu=viewmenu) # 在View菜单内创建Check menu button demoStatus = BooleanVar() demoStatus.set(True) viewmenu.add_checkbutton(label="Status", command=status, variable=demoStatus) root.config(menu=menubar) # 显示菜单对象 statusVar = StringVar() statusVar.set("显示") statusLabel = Label(root, textvariable=statusVar, relief="raised") statusLabel.pack(side="bottom", fill="x") root.mainloop()

执行结果 可参考前面的讲解。

上述程序的重点如下,第23 ~ 26行在View菜单内使用add_checkbutton()创建Check menu button,此对象名称是Status,同时使用demoStatus布尔变量记录目前状态是True或False,这个Status对象当有状态改变时会执行Status()方法。

在第3 ~ 7 行的status()方法中如果目前demoStatus是True,执行第5行包装显示窗口的标签状态栏,相当于显示statusLabel。如果目前demoStatus是False,执行第7行的statusLabel.pack_forget(),这个方法可以隐藏标签状态栏。

16-10 建立工具栏Toolbar

在前面章节中已经学会使用将一系列类似命令组成菜单。在窗口程序设计中,另一个很重要的概念是将常用的命令组成工具栏,放在窗口内以方便用户随时调用。tkinter模块没有提供Toolbar模块,不过我们可以使用Frame建立工具栏。

下面程序实例ch16_11:这个程序会建立一个File菜单,菜单内有Exit命令。这个程序也建立一个工具栏,在工具栏内有exitBtn按钮。这个程序不论是执行File菜单的Exit命令或是单击工具栏中的exitBtn按钮,都可以让程序结束。

from tkinter import * root = Tk() root.title("ch16_11") root.geometry("300x180") menubar = Menu(root) # 建立最上层菜单 # 建立菜单类别对象,并将此菜单类别命名为File filemenu = Menu(menubar, tearoff=False) menubar.add_cascade(label="File", menu=filemenu) # 在File菜单内建立菜单列表Exit filemenu.add_command(label="Exit", command=root.destroy) # 建立工具栏 toolbar = Frame(root, relief=RAISED, borderwidth=3) # 在工具栏内建立按钮 tbPng = PhotoImage(file="tubiao.png") exitBtn = Button(toolbar, image=tbPng, command=root.destroy) exitBtn.pack(side=LEFT, padx=3, pady=3) # 包装按钮 toolbar.pack(side=TOP, fill=X) # 包装工具栏 root.config(menu=menubar) # 显示菜单对象 root.mainloop()

运行结果