14、容器PanedWindow和Notebook
14-1 PanedWindow
14-1-1 PanedWindow基本概念
PanedWindow可以翻译为面板,是一个Widget容器控件,可以在此容器内建立任意数量的子控件。不过一般是在此控件内建立二三个子控件,而控件是以水平方式或垂直方式排列。它的构造方法语法如下。
python
PanedWindow(父对象, options, ...)
参数一:同上
Options:
(1) bg或background:当鼠标光标不在此控件上时,若是有滚动条或方向盒时,滚动条或方向盒的背景颜色。
(2) bd:3D显示时的宽度,默认是2像素。
(3) borderwidth:边界线宽度,默认时2.
(4) cursor:当鼠标光标在标签上方时的光标形状、
(5) handlepad:面板显示宽度,默认是8.。
(6) handlesize:面板显示大小,默认是8。
(7) height:没有默认高度。
(8) orient:面板配置方向默认是HORIZONTAL。
(9) relief:默认是relief=FLAT,可由此控制文字外框。
(10) sashcursor:分隔线光标,没有默认值。
(11) sachrelief:面板分隔线外框,默认是RAISED。
(12) showhandle:滑块属性,可设定是否显示,没有默认值。
(13) width:面板整体宽度,没有默认值。
14-1-2 插入子控件add()
add(child, options)可以插入子对象。
下面程序实例:在PanedWindow对象内插入两个标签子对象,读者可以从缩放窗口了解标签子对象分割此PanedWindow的结果。
python
from tkinter import *
pw = PanedWindow(orient=VERTICAL) # 创建PanedWindow对象
pw.pack(fill=BOTH, expand=True)
top = Label(pw, text="Top pane") # 创建标签Top Pane
pw.add(top) # top标签插入PanedWindow
bottom = Label(pw, text="Bottom pane") # 创建标签Bottom Pane
pw.add(bottom) # bottom标签插入PanedWindow
pw.mainloop()
执行结果

14-1-3 建立LabelFrame当作子对象
PanedWindow是一个面板,最常的应用是将它分成二三份,然后可以将所设计的控件适度分配位置。
下面程序实例ch14_2:设计三个LabelFrame对象当作PanedWindow的子对象,然后水平排列。
python
from tkinter import *
root = Tk()
root.title("ch14_2")
pw = PanedWindow(orient=HORIZONTAL) # 创建PanedWindow对象
leftframe = LabelFrame(pw, text="left Pane", width=120, height=150)
pw.add(leftframe)
middleframe = LabelFrame(pw, text="Middle Pane", width=120)
pw.add(middleframe)
rightframe = LabelFrame(pw, text="Right Pane", width=120)
pw.add(rightframe)
pw.pack(fill=BOTH, expand=True, padx=10, pady=10)
root.mainloop()
执行结果

14-1-4 tkinter.ttk模块的weight参数
ch14_2在执行时,若是更改了窗口的宽度,将看到最右边的面板(Right Pane)放大或缩小,如下所示。

在tkinter.ttk模块中吗,若执行add(子对象, options),在options字段可以增加weight参数,weight代表更改窗口宽度时每个Pane更改的比例,如果插入三个子对象LabelFrame时weight都是1,代表放大或缩小窗口时,三个子对象是相同比例的。
需留意在add()方法内使用weight参数时需要导入tkinter.ttk。
下面程序实例ch14_3:重新设计ch14_2,在插入三个LabelFrame对象时增加weight=1.在执行时若是放大或缩小窗口,可以看到三个LabelFrame子对象是按相同比例更改的。注意程序中导入tkinter.ttk,这是必需的,否则程序会有编译错误。
python
from tkinter import *
from tkinter.ttk import *
root = Tk()
root.title("ch14_3")
pw = PanedWindow(orient=HORIZONTAL) # 创建PanedWindow对象
leftframe = LabelFrame(pw, text="left Pane", width=120, height=150)
pw.add(leftframe, weight=1)
middleframe = LabelFrame(pw, text="Middle Pane", width=120)
pw.add(middleframe, weight=1)
rightframe = LabelFrame(pw, text="Right Pane", width=120)
pw.add(rightframe, weight=1)
pw.pack(fill=BOTH, expand=True, padx=10, pady=10)
root.mainloop()
执行结果

如果三个LabelFrame子对象设置不同的weight,以后更改窗口大小时,彼此会因weight有不同的影响。
下面程序实例ch14_4:设置更改窗口大小时Left Pane的weight=2,Middle Pane的weight=2、Right Pane的weight=1,这代表更改宽度时,更改比例分别是2:2:1。
python
from tkinter import *
from tkinter.ttk import *
root = Tk()
root.title("ch14_4")
pw = PanedWindow(orient=HORIZONTAL) # 创建PanedWindow对象
leftframe = LabelFrame(pw, text="left Pane", width=120, height=150)
pw.add(leftframe, weight=2)
middleframe = LabelFrame(pw, text="Middle Pane", width=120)
pw.add(middleframe, weight=2)
rightframe = LabelFrame(pw, text="Right Pane", width=120)
pw.add(rightframe, weight=1)
pw.pack(fill=BOTH, expand=True, padx=10, pady=10)
root.mainloop()
执行结果

14-1-5 在PanedWindow内插入不同控件
在结束本节前,再介绍一个在PanedWindow内插入不同Widget控件的应用。
下面程序实例:这个程序会先建立PanedWindow,对象名称是pw。然后在它下面的左边建立Entry对象,对象名是entry,下面右边建立另一个PanedWindow对象,对象名称是pwin。最后在pwin对象下面建立Scale对象。
python
from tkinter import *
pw = PanedWindow(orient=HORIZONTAL) # 创建PanedWindow对象
pw.pack(fill=BOTH, expand=True)
entry = Entry(pw, bd=3) # 创建Entry对象
pw.add(entry)
# 创建PanedWindow对象pwin,这是外层PanedWindow的子对象
pwin = PanedWindow(pw, orient=VERTICAL)
pw.add(pwin)
# 创建Scale,这是pwin对象的子对象
scale = Scale(pwin, orient=HORIZONTAL)
pwin.add(scale)
pw.mainloop()
执行结果

14-2 Notebook
Notebook是属于tkinter.ttk模块的控件。
14-2-1 Notebook基本概念
Notebook也是一个Widget容器控件,这个控件的特点是有许多选项卡,当选择不同选项卡时可以看到不同的子控件内容,也可以当作子窗口内容。
使用Notebook()构造方法的语法如下。
python
Notebook(父对象, options)
options参数如下。
(1) height:默认是使用最大可能高度,如果设置数值则使用设置高度。
(2) padding:设置Notebook外围的额外空间,可以设置4个数值代表left、top、right、bottom四周的空间。
(3) width:默认是使用最大可能宽度,如果设置数值则使用设置宽度。
整个建立Notebook框架的步骤如下。
(1) 使用Notebook()建立Notebook对象,假设对象名称是notebook。
(2) 使用notebook对象调用add()方法。
python
add(子对象, text="xxx") # xxx是添加的选项卡名称
(3) 上述代码可以将子对象插入notebook,同时产生"xxx"选项卡名称。
如果用正规语法表示add()方法,它的语法格式如下。
python
add(子对象, options)
options参数如下。
(1) compound:可以设置当选项卡内同时含图像和文字时,彼此之间的位置关系,可以参考2-12节。
(2) image:选项卡以图像方式呈现。
(3) padding:可以设置Notebook和面板Pane的额外空间。
(4) state:可能值是normal、disabled、hidden,如果是disabled表示无法被选取使用,如果是hidden表示被隐藏。
(5) sticky:指出子窗口面板的配置方式,n/s/e/w分别代表North、South、East、West。
(6) text:选项卡中的字符串内容。
(7) underline:从0开始计算的索引,指出第几个字母含下划线。
下面程序实例:简单建立Notebook的框架,这个程序中各选项卡中的子对象是Frame对象,可参考第10、11行。
python
from tkinter import *
from tkinter.ttk import *
root = Tk()
root.title("ch14_6")
root.geometry("300x160")
notebook = Notebook(root) # 创建Notebook
frame1 = Frame() # 创建Frame1
frame2 = Frame() # 创建Frame2
notebook.add(frame1, text="选项卡1") # 创建选项卡1同时插入Frame1
notebook.add(frame2, text="选项卡2") # 创建选项卡2同时插入Frame2
notebook.pack(padx=10, pady=10, fill=BOTH, expand=True)
root.mainloop()
执行结果

14-2-2 绑定选项卡与子控件内容
在程序ch14_6中所看到的各选项卡内容是空的,本节的实例重点是在选项卡内建立子控件内容。
下面程序实例:扩充设计ch14_6,主要是在选项卡1中增加内容是"python"的标签子对象,此时标签对象建立过程可参考第16行,重点如下。
python
label = Label(frame1, ...) # frame1是label的父对象
在选项卡2中增加名称是"Help"的功能按钮子对象,此时功能按钮对象创建过程可参考第19行,重点如下。
python
btn = Button(frame2, ...) # frame2是btn的父对象
当单击Help功能按钮时会列出showinfo内容的消息。
python
from tkinter import *
from tkinter import messagebox
from tkinter.ttk import *
def msg():
messagebox.showinfo('Notebook', '欢迎使用Notebook')
root = Tk()
root.title("ch14_7")
root.geometry("300x160")
notebook = Notebook(root) # 创建Notebook
frame1 = Frame() # 创建Frame1
frame2 = Frame() # 创建Frame2
label = Label(frame1, text="Python") # 在frame1中创建标签控件
label.pack(padx=10, pady=10)
btn = Button(frame2, text="Help", command=msg)
btn.pack(padx=10, pady=10)
notebook.add(frame1, text="页次1") # 创建选项卡1同时插入Frame1
notebook.add(frame2, text="页次2") # 创建选项卡2同时插入Frame2
notebook.pack(padx=10, pady=10, fill=BOTH, expand=True)
root.mainloop()
执行结果

15、进度条Progressbar
15-1 Progressbar的基本使用
Progressbar可以解释为进度条,主要是当作一个工作进度指针,在这个控件中会有一个指针,由此指针可以了解工作进度,例如,档案下载、档案解压缩等。用户可以由这个工作进度指针确认系统仍在进行中,同时也可以了解目前进行到哪一个阶段。
它的构造方法语法如下。
python
Progressbar(父对象, options, ...)
参数一:同上。
options参数:
(1) length:进度条的长度,默认是100像素。
(2) mode:可以有下列两种模式。
①daterminate:一个指针会从起点移至终点,通常当我们知道所需工作时间时,可以使用此模式,这是默认模式。
②indeterminate:一个指针会在起点和重点间来回移动,通常当我们不知道工作所需时间时,可以使用此模式。
(3) maximum:进度条的最大值,默认是100。
(4) name:进度条的名称,供程序参考引用。
(5) orient:进度条的方向,可以是HORIZONTAL(默认)或VERTICAL。
(6) value:进度条的目前值。
(7) variable:记录进度条目前的进度值。
下面程序实例:进度条最大值是100,列出目前值是50的界面。其中一个进度条大部分参数使用默认值,另一个则是使用自定义方式。
python
from tkinter import *
from tkinter.ttk import *
root = Tk()
root.title("ch15_1")
root.geometry("300x140")
# 使用默认创建进度条
pb1 = Progressbar(root)
pb1.pack()
pb1["maximum"] = 100
pb1["value"] = 50
# 使用各参数自定义方式创建进度条
pb2 = Progressbar(root, orient=HORIZONTAL, length=200, mode="determinate")
pb2.pack(pady=20)
pb2["maximum"] = 100
pb2["value"] = 50
root.mainloop()
执行结果
15-2 Progressbar动画设计
如果想要设计含动画效果的Progressbar,可以在每次更新Progressbar对象的value值时调用update()方法,这时窗口可以依据value值重绘,这样就可以达到动画效果。
下面程序实例ch15_2,设计带动画效果的Progressbar,最大值是100,从0开始,每隔0.05s可以移动一格。
python
from tkinter import *
from tkinter.ttk import *
import time
def running():
for i in range(100):
pb["value"] = i + 1
root.update() # 更新画面
time.sleep(0.05)
root = Tk()
root.title("ch15_2")
root.geometry("300x140")
pb = Progressbar(root, orient=HORIZONTAL, length=200, mode="determinate")
pb.pack(padx=10, pady=10)
pb["maximum"] = 100
pb["value"] = 0
btn = Button(root, text="Running", command=running)
btn.pack(pady=10)
root.mainloop()
执行结果

假设我们在设计下载资料的Progressbar,在真实的应用中,可以将所获得的档案大小当作Progressbar对象maximum参数的值,然后设置每次读取数据数量(下载量),只要总下载量小于maximum,则继续下载。
下面是模拟下载的Progressbar设计,假设下载总量是10000B,每次读取数据数量(下载量)是500B。
python
from tkinter import *
from tkinter.ttk import *
import time
def load():
pb["value"] = 0 # 重置进度条
pb["maximum"] = maxbytes
loading()
def loading():
global bytes
bytes += 500
pb["value"] = bytes
if bytes < maxbytes:
pb.after(50, loading)
root = Tk()
root.title("ch15_3")
bytes = 0 # 设置初值
maxbytes = 10000 # 假设下载文件大小
pb = Progressbar(root, orient=HORIZONTAL, length=200, mode="determinate")
pb.pack(padx=10, pady=10)
pb["value"] = 0
btn = Button(root, text="Load", command=load)
btn.pack(pady=10)
root.mainloop()
执行结果

15-3 Progressbar的方法start()/step()/stop()
这几个方法的含义如下。
监听字符串
self.emp_internation.trace_add('write', self.count_salary)
self.emp_internation为创建的字符串变量,ttk.String()
trace_add('write', 函数名),监听字符串变量写入之后需要干什么。
表头组件
创建表格组件
ttk.Treeview(columns='', '', '', show=")
参数
表头标识 columns, 参数后面可以接列表,列表中有几个元素,就增加几个表头
去除默认表头 show="headings"
ttk样式组件
一、基础使用示例
python
style = ttk.Style()
# 查看ttk的组件样式
print(style.theme_names())
# ttk组件主题设置
style.theme_use('')
# 设置默认标签样式
style.configure('TLabel', foreground='red', font=('宋体', 16))
# ttk Label组件参数绑定style='login-TLabel',就可以设置下面样式了
style.configure('login-TLabel', foreground='red', font=('宋体', 16))
# 默认按钮样式
style.configure('TButton', font=('宋体', 12))
# 默认单选框样式
style.configure('TRadiobutton', font=('宋体', 12))
# 默认表头标题
style.configure('Treeview.Heading', font=('宋体', 16))
# 默认表内容样式
style.configure('Treeview', font=('宋体', 14))
ttk.Treeview表格组件
一、基础使用示例
先看一个完整的代码示例,可以直接复制运行:
python
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("简易表格示例")
# 创建表格
table = ttk.Treeview(root)
# 定义列(注意:第一列#0是隐藏的树形列,通常留空)
table["columns"] = ("姓名", "年龄", "城市")
# 设置列属性
table.column("#0", width=0, stretch=tk.NO) # 隐藏第一列
table.column("姓名", width=100, anchor=tk.W) # 列宽度和对齐方式
table.column("年龄", width=60, anchor=tk.CENTER)
table.column("城市", width=120, anchor=tk.E)
# 设置表头
table.heading("姓名", text="姓名") # 列标题
table.heading("年龄", text="年龄")
table.heading("城市", text="城市")
# 添加数据
table.insert("", "end", values=("张三", 25, "北京")) # 插入一行数据
table.insert("", "end", values=("李四", 30, "上海"))
table.insert("", "end", values=("王五", 28, "广州"))
# 显示表格
table.pack(pady=20)
root.mainloop()
二、核心参数详解
1. 列配置(column方法)
-
width:列宽度(单位:像素)
-
anchor :对齐方式(
tk.W左对齐,tk.CENTER居中,tk.E右对齐) -
minwidth:最小宽度(可拖动调整列宽时有效)
-
stretch :是否允许拉伸(
tk.YES/tk.NO)
python
table.column('姓名', anchor='center', width=90)
2. 表头设置(heading方法)
-
text:显示的表头文字
-
command:点击表头时触发的回调函数(用于排序功能)
python
table.heading("年龄", text="年龄", command=lambda: sort_by_age())
3. 插入数据(insert方法)
-
parent:父节点(通常用空字符串表示根节点)
-
index:插入位置("end"表示末尾),tk.END也可以,从最后一行开始追加
-
values:数据内容(元组形式,长度需与列数匹配)
-
iid:可选参数,为行指定唯一标识符
python
table.insert("", "end", iid="row1", values=("张三", 25, "北京"))
4. 其他常用方法
-
删除行 :
table.delete(iid) -
获取选中行 :
table.selection() -
获取行数据 :
table.item(iid, "values") -
修改数据 :
table.item(iid, values=新数据) -
获取选中行的id:table.identify_row(event.y)
-
获取所有行的id:table.get_children()
-
查询id的下标:table.get_children().index(id)
三、样式美化
1. 修改字体颜色
python
style = ttk.Style()
style.configure("Treeview",
rowheight=25, # 行高
font=("微软雅黑", 11),
foreground="#333",
background="#fff")
# 设置斑马线效果(隔行变色)
style.map("Treeview", background=[("selected", "#0078D7"), ("!selected", "#f0f0f0")])
2. 添加滚动条
python
# 纵向滚动条
y_scroll = ttk.Scrollbar(root, orient="vertical", command=table.yview)
table.configure(yscrollcommand=y_scroll.set)
y_scroll.pack(side=tk.RIGHT, fill=tk.Y)
# 横向滚动条同理(orient="horizontal")
四、常见问题
-
为什么表格不显示数据?
-
检查是否执行了
insert插入数据 -
确认列名与
columns定义一致
-
-
如何实现点击排序?
需要自定义排序函数:
pythondef sort_by_col(col, reverse): data = [(table.set(child, col), child) for child in table.get_children("")] data.sort(reverse=reverse) for index, (val, child) in enumerate(data): table.move(child, "", index) table.heading(col, command=lambda: sort_by_col(col, not reverse)) -
如何获取选中行数据?
pythonselected = table.selection() if selected: print(table.item(selected[0], "values"))
五、完整功能示例(带编辑功能)
python
# 点击单元格编辑功能
def edit_cell(event):
region = table.identify_region(event.x, event.y)
if region == "cell":
column = table.identify_column(event.x)
iid = table.focus()
current_value = table.item(iid, "values")[int(column[1])-1]
# 创建编辑框
entry = tk.Entry(root)
entry.place(x=event.x, y=event.y)
entry.insert(0, current_value)
def save_edit():
new_value = entry.get()
values = list(table.item(iid, "values"))
values[int(column[1])-1] = new_value
table.item(iid, values=values)
entry.destroy()
entry.bind("<Return>", lambda e: save_edit())
table.bind("<Double-1>", edit_cell)
滚动条ttk.Scrollbar
用于滚动一些组件的可见范围,根据方向可分为垂直滚动条和水平滚动条。组件常常被用于实现文本、画布和列表框的滚动。
在名为parent的顶级窗口或框架中创建一个新的滚动条组件:
python
# 创建滚动条 command=需要绑定的应用组件,yview
scroll_bar = ttk.Scrollbar(main_window, command=table.yview)
# 表格绑定滚动条
table.config(yscrollcommand=scroll_bar.set)
# 滚动条布局
scroll_bar.place(x=1313, y=80, height=645)