Tkinter库的学习记录-6

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")

四、常见问题

  1. 为什么表格不显示数据?

    • 检查是否执行了 insert 插入数据

    • 确认列名与 columns 定义一致

  2. 如何实现点击排序?

    需要自定义排序函数:

    python 复制代码
    def 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))
  3. 如何获取选中行数据?

    python 复制代码
    selected = 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)