18.Tkinter布局管理控件
Tkinter 还提供了几个常用的布局管理控件,比如 Frame 、LabelFrame 等,这些控件的主要作用是为其他控件提供载体,并将主窗口界面划分成多个区域,从而方便开发者对不同区域进行设计与管理。
在前文讲解其他的 Tkinter 控件时,我们列举的大多数示例都是将控件直接放置在主窗口(即根窗口)内,这样做的目的是为了便于大家理解。但在实际的开发过程中,控件一般放置在容器中,比如 Frame 容器控件,如同 HTML 中的<div>
标签一样,把容器看做成一个框架,其他控件则是这个框架中的“元素”。
本节介绍了四种常用的容器控件以及它们的使用方法,分别是 Frame、LabelFrame、PanedWindow 以及 Toplevel。
Frame控件
Frame 本质上也是一个矩形窗体,同其他控件一样也需要位于主窗口内。我们可以在主窗口内放置多个 Frame 控件,并且每个 Frame 中还可以嵌套一个或者多个Frame,从而将主窗口界面划分成多个区域。
Frame 控件的常用属性如下表所示:
属性 | 说明 |
---|---|
bg | 设置 Frame 的背景颜色 |
bd | 指定 Frame 的边框宽度 |
colormap | 指定 Frame 组件及其子组件的颜色映射 |
container | 布尔值参数,若参数值为 True,则窗体将被用作容器使用,一些其他程序也可以被嵌入。 |
cursor | 指定鼠标在 Frame 上飘过的鼠标样式,默认由系统指定 |
height/width | 设置 Frame 的高度和宽度 |
highlightbackground | 指定当 Frame 没有获得焦点的时候高亮边框的颜色,通常由系统指定为标准颜色 |
highlightcolor | 指定当 Frame 获得焦点的时候高亮边框的颜色 |
highlightthickness | 指定高亮边框的宽度,默认值是 0 |
padx/pady | 距离主窗口在水平/垂直方向上的外边距 |
relief | 指定边框的样式,参数值 "sunken","raised","groove" 或 "ridge","flat",默认为 "falt' |
takefocus | 布尔值参数,默认为 False,指定该组件是否接受输入焦点(即用户通过 Tab 键将焦点转移上来) |
下面看一组简单的示例,通过 Frame 将主窗口分成左右两个部分,如下所示:
- import tkinter as tk
- win = tk.Tk()
- win.title("C语言中文网")
- win.geometry('400x350+200+200')
- win.iconbitmap('C:/Users/Administrator/Desktop/C语言中文网logo.ico')
- # 在主窗口上添加一个frame控件
- frame1 = tk.Frame(win)
- frame1.pack()
- # 在frame_1上添加另外两个frame, 一个在靠左,一个靠右
- #左侧的frame
- frame_left = tk.Frame(frame1)
- tk.Label(frame_left,text='左侧标签1',bg='green',width=10,height=5).grid(row =0,column=0)
- tk.Label(frame_left,text='左侧标签2',bg='blue',width=10,height=5).grid(row = 1 ,column =1)
- frame_left.pack(side=tk.LEFT)
- frame_right = tk.Frame(frame1)
- tk.Label(frame_right,text='右侧标签1',bg='gray',width=10,height=5).grid(row = 0 ,column =1)
- tk.Label(frame_right,text='右侧标签2',bg='pink',width=10,height=5).grid(row = 1 ,column =0)
- tk.Label(frame_right,text='右侧标签3',bg='purple',width=10,height=5).grid(row= 1,column=1)
- frame_right.pack(side=tk.RIGHT)
- win.mainloop()
程序运行结果:
![tkinter frame容器控件](http://c.biancheng.net/uploads/allimg/220105/11403142D-0.gif)
图1:Frame控件布局管理
上述示例利用 Frame 控件将主窗口分成了左右两个子区域,同时在各自区域中添加了 Label 标签,而且区域之间互不干扰。采用这种分区、分块的布局方式,可以使得 GUI 程序更加规范、简洁化。
LabelFrame控件
LabelFrame 控件也是一种容器类型的控件,它属于是 Frame 控件的变体,因此它们的属性选项大体相同。
在默认情况下,LabelFrame 会在其包裹的子组件周围绘制一个边框和一个标题。当我们想要将一些相关的组件分为一组时,就可以使用 LabelFrame 组件,比如把一系列 Radiobutton(单选按钮)放在一起来供用户选择。
同 Frame 控件一样,LabelFrame 的主要作用也是对控件进行分组处理,下面看一个具体的实例:
- import tkinter as tk
- win = tk.Tk()
- win.title("C语言中文网")
- win.geometry('800x350+200+200')
- win.iconbitmap('C:/Users/Administrator/Desktop/C语言中文网logo.ico')
- # 定义第一个容器,使用 labelanchor ='w' 来设置标题的方位
- frame_left = tk.LabelFrame(win, text="教程", labelanchor="w",bg='#5CACEE')
- # 使用 place 控制 LabelFrame 的位置
- frame_left.place(relx=0.2, rely=0.2, relwidth=0.2, relheight=0.5)
- label_1 = tk.Label(frame_left, text="C语言")
- label_1.place(relx=0.2, rely=0.2)
- label_2 = tk.Label(frame_left, text="Python")
- label_2.place(relx=0.6, rely=0.2)
- label_3 = tk.Label(frame_left, text="Java")
- label_3.place(relx=0.2, rely=0.6)
- label_4 = tk.Label(frame_left, text="C++")
- label_4.place(relx=0.6, rely=0.6)
- # 定义第二个容器,使用 labelanchor ='w' 来设置标题的方位
- frame_right = tk.LabelFrame(win, text="辅导班", labelanchor="w",bg='#66CDAA')
- # 使用 place 控制 LabelFrame 的位置
- frame_right.place(relx=0.5, rely=0.2, relwidth=0.3, relheight=0.6)
- label_1 = tk.Label(frame_right, text="C语言辅导班")
- label_1.place(relx=0.2, rely=0.2)
- label_2 = tk.Label(frame_right, text="数据结构")
- label_2.place(relx=0.6, rely=0.2)
- label_3 = tk.Label(frame_right, text="C++辅导班")
- label_3.place(relx=0.2, rely=0.6)
- label_4 = tk.Label(frame_right, text="Python答疑")
- label_4.place(relx=0.6, rely=0.6)
- win.mainloop()
程序运行结果:
![tkinter LableFrame容器控件](http://c.biancheng.net/uploads/allimg/220105/1140313229-1.gif)
图2:LabelFrame容器控件
PanedWindow控件
PanedWindow(窗格界面)也可以理解成一个特殊的 Frame 控件,它是 Tkinter 8.4 版本后新增的空间管理组件,其主要目的是为其他组件提供一个容器或者框架,从而实现以分块的形式对图形界面进行布局。
与 Frame 控件不同, PanedWindow 允许用户自主地调整界面划分以及每块区域的大小。因此,当您需要让用户自己调节每块区域的大小时,就可以采用 PanedWindow 作为组件载体来进行界面的布局。
不仅如此 PanedWindow 组件还提供了“手柄” 功能(设置参数 showhandle=True 来启用),通过拖动“手柄”图标也可以改变每块区域的大小。PanedWindow 组件语法格式如下所示:
PanedWindow(master=None, **options)
其中 master 表示父组件,即包裹该组件的上层组件。其常用属性如下表所示:
属性 | 说明 |
---|---|
handlepad | 1. 调节“手柄”的位置 2. 比如当 orient ='vertical' 设置垂直时,handlepad 表示“分割线”上的手柄与左端的距离,默认为 8 像素 |
handlesize | 设置“手柄”的尺寸(由于“手柄”必须是一个正方形,所以是设置正方形的边长)默认为 8 像素 |
opaqueresize | 1. 该选项定义了用户调整窗格尺寸的操作,如果该选项的值为 True(默认),窗格的尺寸随用户鼠标的拖拽而改变 2. 如果该选项的值为 False,那么窗格的尺寸,在用户释放鼠标时才会更新到新的位置上 |
orient | 指定窗格的分布方式,默认为水平方向分布("horizontal"),或者还可以设置为垂直纵向分布("vertical") |
relif | 指定边框的样式,默认为 "flat",还可以设置为 "sunken","raised","groove" 或 "ridge" |
sashpad | 设置每一条分割线到窗格间的间距 |
sashrelief | 设置分割线的样式,默认值是:"flat",还可以设置 "sunken","raised","groove" 或 "ridge" |
sashwidth | 设置分割线的宽度 |
showhandle | 设置是否显示调节窗格的手柄,默认为 False |
height/width | 设置 PanedWindow 的高度、宽度,若不设置,则其大小由其子组件的尺寸决定 |
PanedWindow 的常用方法如下表所示:
方法 | 说明 |
---|---|
add(child) | 添加一个新的子组件到窗格中语法格式 add(child,**option),参数值 after、before、sticky |
forget(child) | 删除一个子组件 |
panecget(child, option) | 获得子组件指定选项的值 |
paneconfig(child, **options) | 设置子组件的各种选项 |
panes() | 将父组件中包含的子组件以列表的形式返回 |
sash_coord(index) | 返回一个二元组表示指定分割线的起点坐标 |
sash_place(index, x, y) | 将指定的分割线移动到一个新的位置 |
下面示例设计一个简单的界面布局,然后将图形界面分割成四部分:创建一个水平方向的 PanedWindow,并向其中添加两个 Label 组件,之后创建一个垂直的方向的 PanedWindow,并向其中中添加两个 Label 标签。示例代码如下:
- import tkinter as tk
- win = tk.Tk()
- win.title("C语言中文网")
- win.geometry('400x400+200+200')
- win.iconbitmap('C:/Users/Administrator/Desktop/C语言中文网logo.ico')
- # 创建一个水平方向的 panedwindow,并添加到主窗口中,默认为水平方向
- p_window1 = tk.PanedWindow(win)
- p_window1.pack(fill=tk.BOTH, expand=1)
- # 在窗口区的左侧添加两个水平方向的 Label
- left1 =tk. Label(p_window1, text='C语言中文网', bg='#7CCD7C', width=10,font=('微软雅黑',15))
- p_window1.add(left1)
- left2 =tk.Label(p_window1, text='网址:c.biancheng.net', bg='#9AC0CD', width=10,font=('微软雅黑',15))
- p_window1.add(left2)
- # 创建一个垂直方向的panedwindow,并添加一个手柄,设置分割线样式
- p_window2 = tk.PanedWindow(orient=tk.VERTICAL,showhandle=True,sashrelief='sunken')
- # 添加到 p_window1中
- p_window1.add(p_window2)
- # 在 p_window2 中添加两个垂直方向的标签
- top_label =tk. Label(p_window2, text='教程', bg='#7171C6', height=8,font=('宋体',15))
- p_window2.add(top_label)
- bottom_label =tk. Label(p_window2, text='辅导班', bg='#8968CD',font=('宋体',15))
- p_window2.add(bottom_label)
- win.mainloop()
程序运行结果:
![tkinter panedwindow容器组件](http://c.biancheng.net/uploads/allimg/220105/114031M08-2.gif)
图3:PanedWindow空间布局
注意:从上述示例中可以看出 PanedWindw 会为每一个 Label 控件创建一个独立的窗格, 当我们将鼠标悬停在两个控件接壤处的白色边框上时,就会出现可以上下或者左右拉伸的指示光标,用户按照可以按照自己的意愿来调整每块区域的大小。
Toplevel控件
Topleve 是一个顶级窗口控件(也被称为“子窗体”控件),同样类似于 Frame 控件, 不过该控件会脱离根窗口另行创建一个独立窗口,因此它的存在形式不同于上述其他容器。
Toplevel 控件同样隶属于主窗口的子组件,只是存在形式特殊而已。Toplevel 是主窗口之外的弹出框窗口(通过事件来触发执行),在这个窗口内也可以包含其他组件。但需要注意,顶级窗口并不是必须位于窗口的顶部位置,之所以称其为顶级窗口,是因为相对于主窗口而言,Topleve 位于主窗口的上一层。
Toplevel 控件拥有根窗口控件的所有方法和属性,同时它还拥有一些独有的方法,如下表所示:
方法 | 说明 |
---|---|
deiconify() | 在使用 iconify() 或 withdraw() 方法后,即窗口最小化和移除窗口后(只是看不见,并没销毁),使用该方法来显示该窗口 |
frame() | 返回一个系统特定的窗口识别码 |
group(window) | 将顶级窗口加入 window 窗口群组中,如果忽略该参数,将返回当前窗口群的主窗口 |
iconify() | 将窗口图标化(最小化),需要重新显示窗口,使用 deiconify() 方法 |
protocol(name, function) | 将回调函数 function 与相应的规则 name 绑定; 1) name 参数可以是 "WM_DELETE_WINDOW":窗口被关闭的时候; 2) name 参数可以是 "WM_SAVE_YOURSELF":窗口被保存的时候; 3) name 参数可以是 "WM_TAKE_FOCUS":窗口获得焦点的时候。 |
state() | 设置和获得当前窗口的状态,参数值 "normal"(正常状态),"withdrawn(移除窗口)","icon"(最小化)和 "zoomed"(放大) |
transient(master) | 指定为 master 的临时窗口 |
withdraw() | 将窗口从屏幕上移除,只是移动到了窗口之外,并没销毁,需要重新显示窗口,使用 deiconify() 方法 |
下面看一组关于创建 Toplevel 的示例,如下所示:
- import tkinter as tk
- root = tk.Tk()
- root.config(bg='#87CEEB')
- root.title("C语言中文网")
- root.geometry('400x350+300+300')
- root.iconbitmap('C:/Users/Administrator/Desktop/C语言中文网logo.ico')
- def create_toplevel():
- top = tk.Toplevel()
- top.title("C语言中文网")
- top.geometry('300x200+100+100')
- top.iconbitmap('C:/Users/Administrator/Desktop/C语言中文网logo.ico')
- # 多行文本显示Message控件
- msg = tk.Label(top, text="网址:c.biancheng.net",bg='#9BCD9B',font=('宋体',15))
- msg.pack()
- tk.Button(root, text="点击创建Toplevel组件", width=20,height=3,command=create_toplevel).pack()
- root.mainloop()
程序的运行结果如下:
![toplevel组件顶级窗口](http://c.biancheng.net/uploads/allimg/220105/114031G28-3.gif)
图4:Toplevel组件创建顶级窗口