示例3#

如果有多个 tkinter 或者 Ttk 小部件,那么该如何布局它们?本章将利用 Grid 的方式展示 tkinter 的布局管理。

LabelFrame 小部件中排列多个标签#

标签框架小部件 LabelFrame 允许我们以有组织的方式设计我们的 GUI。

from tkinter import ttk, Tk

# 创建一个窗口实例
win = Tk()

# 为窗口添加标题
win.title("Python GUI")
ttk.Label(text='LabelFrame').grid(column=0, row=0) 
# 创建一个容器(container)来保存标签。
buttons_frame = ttk.LabelFrame(win, text=' Labels in a Frame ')
buttons_frame.grid(column=1, row=0) 
# 将标签放入容器元素(container element)
ttk.Label(buttons_frame, text="Label1").grid(column=0, row=0, sticky='w')
ttk.Label(buttons_frame, text="Label2").grid(column=1, row=0, sticky='w')
ttk.Label(buttons_frame, text="Label3").grid(column=2, row=0, sticky='w')

# 启动 GUI
win.mainloop()

图2.1  小部件中排列多个标签

可以不填写 LabelFrame 小部件的名称,并且将 label 竖直排列:

from tkinter import ttk, Tk

# 创建一个窗口实例
win = Tk()

# 为窗口添加标题
win.title("Python GUI")
ttk.Label(text='LabelFrame').grid(column=0, row=0) 
# 创建一个容器(container)来保存标签。
buttons_frame = ttk.LabelFrame(win, text='')
buttons_frame.grid(column=1, row=0) 
# 将标签放入容器元素(container element)
ttk.Label(buttons_frame, text="Label1").grid(column=0, row=0)
ttk.Label(buttons_frame, text="Label2").grid(column=0, row=1)
ttk.Label(buttons_frame, text="Label3").grid(column=0, row=2)

# 启动 GUI
win.mainloop()

效果图:

图2.2 在 LabelFrame` 小部件中竖直排列标签

使用填充添加小部件周围的空间#

上面的 LabelFrame 看起来有点拥挤,因为它与主窗口混合到底部。现在让我们来解决这个问题:在 buttons_frame 内部添加空白:

for child in buttons_frame.winfo_children(): 
    child.grid_configure(padx=8, pady=4)

效果图:

图2.3 使用填充在  内部添加空白

也可以直接在 buttons_frame 上添加空白:

buttons_frame.grid(column=0, row=1, padx=20, pady=40) 

图2.4 使用填充在  周围添加空白

综合上述两种添加空白的方法得到:

图2.5 使用填充添加小部件周围的空间

创建菜单栏#

创建菜单栏是 GUI 的“主菜”:

from tkinter import Tk, Menu, ttk

# 创建一个窗口实例
win = Tk()

# 为窗口添加标题
win.title("Python GUI")

# 创建 Menu Bar
menu_bar = Menu(win)
win.config(menu=menu_bar)

# 创建 menu 并添加 menu items
file_menu = Menu(menu_bar)              # 创建File menu
file_menu.add_command(label="新建")   # 添加 File menu item
# 添加分隔线
file_menu.add_separator()
file_menu.add_command(label="退出")

# 添加File menu 到 menu bar 并给予一个标签
menu_bar.add_cascade(label="文件", menu=file_menu)

# 启动 GUI
win.mainloop()

效果图:

图2.6 可分离的创建菜单栏

通过将 tearoff 属性传递给菜单的构造函数,我们可以删除默认情况下出现在菜单中第一个菜单项上方的第一个虚线来禁用菜单栏的分离:

file_menu = Menu(menu_bar, tearoff=0)

效果图:

图2.7 不可分离的创建菜单栏

在菜单栏添加新的菜单:

# 将另一个菜单添加到菜单栏和项目
help_menu = Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="帮助", menu=help_menu)
help_menu.add_command(label="关于")

效果图:

图2.8 添加“帮助”菜单

此时,我们的 GUI 具有菜单栏和两个包含一些菜单项的菜单。在我们添加一些命令之前,单击它们不会执行任何操作。这就是我们接下来要做的。在创建菜单栏时添加以下代码:

# 退出 GUI
def _quit():
    win.quit()
    win.destroy()

接着,在“退出”菜单选项中添加 command 配置选项:

file_menu.add_command(label="退出", command=_quit)

现在,当我们单击 "退出" 菜单项时,我们的应用程序确实会退出。

我们也需要为“关于”菜单创建命令弹出消息盒子:

from tkinter import messagebox as msg
def _msgBox():
    msg.showinfo(title="Python 消息信息框", 
                 message='使用 tkinter:\n 年份是 2020 年创建的 Python GUI。')  
...
help_menu.add_command(label="关于", command=_msgBox) # 单击时显示消息框

# 启动 GUI
win.mainloop()

效果图:

图2.9 消息盒子 Info

也可以设定为警告:

def _msgBox():
    msg.showwarning('Python 消息警告框',
                    '使用 tkinter 创建的 Python GUI: \n警告:此代码中可能存在 bug。')

显示:

图2.10 消息警告框

弹出错误框:

def _msgBox():
    msg.showerror('Python 消息错误框',
                    '使用 tkinter 创建的 Python GUI: \n错误:我们确实有一个严重的问题!')

显示:

图2.11 错误框

弹出多选框:

def _msgBox():
    answer = msg.askyesnocancel("Python 消息多选择框", "你确定你真的想这么做吗?")
    print(answer)

显示:

图2.12 多选框

此框是有返回值的,选择"是",“否”,“取消” 分别返回:TrueFalseNone

创建选项卡式小部件:ttk.Notebook#

为了充分地利用窗口的空间,创建选项卡式小部件(tabbed widgets )是十分有必要的:

from tkinter import Tk, Menu, ttk

# 创建一个窗口实例
win = Tk()

# 为窗口添加标题
win.title("Python GUI")

# 创建 Tab Control(选项卡控件)
tabControl = ttk.Notebook(win)
tab1 = ttk.Frame(tabControl)        # 创建选项卡(tab)
tabControl.add(tab1, text='Tab 1')      # 添加tab

tab2 = ttk.Frame(tabControl)            # 再添加一个 tab
tabControl.add(tab2, text='Tab 2')

tabControl.pack(expand=1, fill="both")  # pack 以使其可见
# 启动 GUI
win.mainloop()

效果图:

图2.13 创建带有选项卡的 Notebook

为其中一个选项卡添加 LabelFrame:

from tkinter import Tk, Menu, ttk
...

# 使用 tab1 作为父级的标签框架
mighty = ttk.LabelFrame(tab1, text=' Mighty Python ')
mighty.grid(column=0, row=0, padx=8, pady=4)

# 使用mighty作为父级的标签
a_label = ttk.Label(mighty, text="键入名称:")
a_label.grid(column=0, row=0, sticky='W')

# 启动 GUI
win.mainloop()

图2.14 为其中一个选项卡添加 LabelFrame