环境

  • Python版本:3.8+
  • ttkbootstrap版本:1.11.0

避坑提示:ttkbootstrap版本大于1.11时,Meter控件amountused不支持小数显示。

代码

# !/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Creator: Wang
Date: 2025/8/1
Description: 基于tk的ttkbootstrap框架桌面开发示例代码
"""
import time
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.dialogs import Messagebox
from tkinter import filedialog


# 按钮1提示框点击事件
def btn1_click():
    Messagebox.show_info(
        str(chk_var.get())
        + "," + str(rao_var.get())
        + "," + str(comb_var.get())
        + "," + str(date_obj.entry.get())
        + "," + str(entry_var.get())
        , "来自ttk提示", position=CENTER)


# 按钮2洪水进度条点击事件
def btn2_click():
    for i in range(101):
        fldg_obj.configure(value=i)  # 动态修改组件,用configure
        root.update()
        time.sleep(0.01)
    Messagebox.show_info("完成!")


# 按钮3环形进度点击事件
def btn3_click():
    for i in range(101):
        meter_obj.configure(amountused=i)  # 动态修改组件,用configure
        if i == 100: meter_obj.configure(subtext="处理完成")
        root.update()
        time.sleep(0.01)
    Messagebox.show_info("完成!")


# 按钮4普通进度条点击事件
def btn4_click():
    for i in range(101):
        pb_obj.configure(value=i)  # 动态修改组件,用configure
        pb_label_obj.config(text=f"当前进度:{i}%")
        root.update()
        time.sleep(0.01)
    Messagebox.show_info("完成!")


# 浏览文件按钮点击事件
def file_btn_click():
    path = filedialog.askopenfilename(title="选择Excel文件", filetypes=[("Excel文件", "*.xls"), ("Excel文件", "*.xlsx")])
    if path:
        file_entry_var.set(path)
        file_entry_obj.focus_set()
        file_entry_obj.icursor("end")


# 菜单-文件-打开
def open_file():
    Messagebox.show_info("打开文件")


# 菜单-文件-另存
def save_other_file():
    Messagebox.show_info("另存文件")


# 菜单-帮助-关于
def show_about():
    Messagebox.show_info("Demo演示系统v1.0\n开发者:Wong\n\n©版权所有 2025")


# 创建一个窗口
# title:窗口标题; size:窗口大小
# root.update():刷新界面元素,此方法也可防止界面阻塞
root = ttk.Window(title="ttk演示系统", size=(1600, 1200))

# Checkbutton,Radiobutton,Combobox表单元素绑定值之前,先声明变量/类型
# value:默认赋值
# 以下变量声明必须在ttk.Window()初始化之后!
chk_var = ttk.BooleanVar(value=TRUE)
rao_var = ttk.StringVar(value="0")
comb_var = ttk.StringVar(value="")
date_var = ttk.StringVar(value="")
entry_var = ttk.StringVar(value="")
# fldg_var = ttk.StringVar(value="")
# meter_var = ttk.StringVar(value="")
file_entry_var = ttk.StringVar(value="")

# 按钮-Button
# text:按钮文本; bootstyle:显示样式,支持元组多个值; command:监听事件函数
# grid():表格布局类型; row:第几行; column:第几列; padx:水平间隔; pady:垂直间隔; sticky:布局中对齐方式(W西 E东)
# pack():自动布局类型, anchor=NW:靠左上角, fill=X:水平填充, side=LEFT:左浮动之意
# pack布局在使用side=LEFT之后就不能换行布局了,若需要换行布局,则创建Frame容器,将组件放入Frame容器中,Frame容器会新起一行。如 fr_row1 = ttk.Frame(root)  fr_row1.pack(padx=10, pady=10, anchor=NW)
ttk.Button(root, text="按钮1 提示框", bootstyle=SUCCESS, command=btn1_click).grid(row=1, column=1, padx=10, pady=15, sticky=W)
ttk.Button(root, text="按钮2 洪水进度条", bootstyle=PRIMARY, command=btn2_click).grid(row=1, column=2, padx=10, pady=15, sticky=W)
ttk.Button(root, text="按钮3 环形进度", bootstyle=DANGER, command=btn3_click).grid(row=1, column=3, padx=10, pady=15, sticky=W)
ttk.Button(root, text="按钮4 普通进度条", bootstyle=INFO, command=btn4_click).grid(row=1, column=4, padx=10, pady=15, sticky=W)

# 复选框-Checkbutton
# variable:动态绑定变量
ttk.Checkbutton(root, text="选择", bootstyle=(ROUND, TOGGLE), variable=chk_var).grid(row=2, column=1, padx=10, pady=15, sticky=W)

# 单选按钮-Radiobutton
# variable:动态绑定变量
ttk.Radiobutton(root, text="精确", value="1", variable=rao_var).grid(row=2, column=2, padx=10, pady=15, sticky=W)
ttk.Radiobutton(root, text="模糊", value="0", variable=rao_var).grid(row=2, column=3, padx=10, pady=15, sticky=W)

# 文本标签-Label
ttk.Label(root, text="选择一项:").grid(row=3, column=1, padx=10, pady=15, sticky=W)

# 下拉组合框-Combobox
# textvariable:动态绑定文本变量,注意不是variable; columnspan:独占列数
ttk.Combobox(root, values=["Python", "Java", "C++", "Go", "PHP"], textvariable=comb_var, state="readonly").grid(row=3, column=2, columnspan=2, pady=15, sticky=W)

# 日期-DateEntry
# width:宽度; dateformat:日期格式化
# **特别提醒**:当组件链式调用布局管理方法(grid/pack/place),得到的是布局管理返回值,而非组件对象,如需得到组件对象,需要将组件创建和布局管理分开操作(其它组件亦然)
# 取值方法:date_obj.entry.get()
date_obj = ttk.DateEntry(root, width=15, dateformat=r"%Y-%m-%d")
date_obj.grid(row=3, column=4, columnspan=2, padx=10, pady=15, sticky=W)

# 输入框-Entry
# textvariable:动态绑定文本变量,注意不是variable
ttk.Entry(root, width=20, textvariable=entry_var).grid(row=3, column=6, columnspan=2, padx=10, pady=15, sticky=W)

# 洪水进度条-Floodgauge
# length:显示长度(宽度); value:当前值; maximum:最大值; textvariable:动态绑定文本变量; mask:进度条上显示的文本模板({}会被替换为当前进度值)
fldg_obj = ttk.Floodgauge(root, mask="当前进度 {}%", length=500, value=0, maximum=100, bootstyle=SUCCESS)
fldg_obj.grid(row=4, column=1, columnspan=4, padx=10, pady=15, sticky=W)

# 菜单栏-Menu
# tearoff=0:菜单固定,不可浮动
menu_bar = ttk.Menu(root)  # 先创建菜单条
file_menu = ttk.Menu(menu_bar, tearoff=0)  # [文件]菜单
file_menu.add_command(label="打开", command=open_file)
file_menu.add_command(label="另存", command=save_other_file)
file_menu.add_separator()  # 分割线
file_menu.add_command(label="退出", command=root.quit)
menu_bar.add_cascade(label="文件", menu=file_menu)  # 菜单条添加[文件]菜单

help_menu = ttk.Menu(menu_bar, tearoff=0)  # [帮助]菜单
help_menu.add_command(label="关于", command=show_about)
menu_bar.add_cascade(label="帮助", menu=help_menu)  # 菜单条添加[帮助]菜单
# 主窗口添加菜单条
root.config(menu=menu_bar)

# 环形进度条-Meter
# metersize:显示大小; amountused:当前进度; amounttotal:最大值; meterthickness:进度条厚度; stripethickness:条纹厚度(用于分段效果); textvariable:动态绑定文本变量
meter_obj = ttk.Meter(root, metersize=150, amountused=0, amounttotal=100, meterthickness=10, stripethickness=10, textleft="进度", textright="%", subtext="正在处理中...")
meter_obj.grid(row=5, column=1, columnspan=4, padx=10, pady=15, sticky=W)

# 标签页-Notebook
# width:宽度; height:高度
notebook_obj = ttk.Notebook(root, bootstyle="info", width=800, height=100)  # 初始化Notebook组件
notebook_obj.grid(row=6, column=1, columnspan=10, padx=10, pady=15, sticky=W)
tab1 = ttk.Frame(notebook_obj)  # 第一个标签
notebook_obj.add(tab1, text="基本信息区")    # 在Notebook中添加标签页
ttk.Label(tab1, text="基本信息区中的内容").grid(row=1, column=1, columnspan=1, padx=10, pady=15)
tab2 = ttk.Frame(notebook_obj)  # 第二个标签
notebook_obj.add(tab2, text="系统设置区")    # 在Notebook中添加标签页
ttk.Label(tab2, text="系统设置区中的内容").grid(row=1, column=1, columnspan=1, padx=10, pady=15)

# 普通进度条-Progressbar
pb_obj = ttk.Progressbar(root, length=300, value=30, maximum=100, bootstyle=STRIPED)
pb_obj.grid(row=7, column=1, columnspan=2, padx=10, pady=15, sticky=W)
pb_label_obj = ttk.Label(root, text="当前进度:30%")
pb_label_obj.grid(row=7, column=3, padx=10, pady=15, sticky=W)

# 滑动条-Scale
# from_:起始值; to:终点值
scale_obj = ttk.Scale(root, length=300, from_=0, to=100, value=50, bootstyle="warning")
scale_obj.grid(row=7, column=4, columnspan=2, padx=10, pady=15, sticky=W)

# 分割线-Separator
# grid布局时,通过columnspan和sticky=EW控制长度
# pack布局时,通过fill=X控制长度
ttk.Label(root, text="分割线").grid(row=8, column=1, columnspan=1, padx=10, pady=15, sticky=W)
ttk.Separator(root).grid(row=8, column=2, columnspan=6, padx=10, pady=15, sticky=EW)

# 文件对话框-采用 tkinter 的 filedialog.askopenfilename() 方法
# state=READONLY:输入框只读
ttk.Label(root, text="选择Excel文件").grid(row=9, column=1, columnspan=1, padx=10, pady=15, sticky=W)
file_entry_obj = ttk.Entry(root,  width=40, textvariable=file_entry_var)
file_entry_obj.grid(row=9, column=2, columnspan=2, padx=10, pady=15, sticky=W)
ttk.Button(root, text="浏览", bootstyle=PRIMARY, command=file_btn_click).grid(row=9, column=4, padx=10, pady=15, sticky=W)


# 模拟无限循环进度条
def infinite_progress():
    current = pb_loop_obj["value"]  # 取进度条的值
    if current < 100:
        # 动态调整样式
        if current < 30:
            pb_loop_obj.configure(bootstyle=(STRIPED, DANGER))
        elif 30 <= current < 70:
            pb_loop_obj.configure(bootstyle=(STRIPED, WARNING))
        else:
            pb_loop_obj.configure(bootstyle=(STRIPED, SUCCESS))

        pb_loop_obj["value"] = current + 1
    else:
        pb_loop_obj["value"] = 0  # 重置进度条
    global after_id
    after_id = root.after(30, infinite_progress)  # x ms后继续执行,after()返回after_id,方便将来根据它结束after


# 根据after_id结束after
def stop_progress(after_id):
    root.after_cancel(after_id)
    pb_loop_obj["value"] = 0


pb_loop_obj = ttk.Progressbar(root, length=300, value=0, maximum=100, bootstyle=STRIPED)
pb_loop_obj.grid(row=10, column=1, columnspan=2, padx=10, pady=15, sticky=W)
ttk.Button(root, text="启动进度条", bootstyle=SUCCESS, command=infinite_progress).grid(row=10, column=3, padx=10, pady=15, sticky=W)
ttk.Button(root, text="结束进度条", bootstyle=PRIMARY, command=lambda: stop_progress(after_id)).grid(row=10, column=4, padx=10, pady=15, sticky=W)

# 滚动条文本域-ScrolledText
# height:高度; width:宽度; 起始位置为1.0(首行首字符),结束位置为END
# 文本插入:text_obj.insert(END, "插入的文本内容"); 文本获取:text_obj.get("1.0", END); 文本清空:text_obj.delete("1.0", END); 自动滚动至底部:text_obj.see(END)
ttk.Label(root, text="日志输出:").grid(row=11, column=1, padx=10, pady=15, sticky=W)
text_obj = ttk.ScrolledText(root, height=4, width=100)
text_obj.grid(row=12, column=1, columnspan=10, padx=10, pady=15, sticky=W)


# 渲染界面
root.place_window_center()  # 使窗口屏幕居中
root.mainloop()

效果

<转载请注明出处>

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐