尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Python GUI美化利器:ttkbootstrap让Tkinter拥有现代界面

Python GUI美化利器:ttkbootstrap让Tkinter拥有现代界面 1. 从Tkinter的“土味”到现代UI的跨越如果你用Python写过桌面图形界面大概率绕不开Tkinter。它作为Python的标准GUI库优点是开箱即用、无需额外安装但它的默认样式用现在的话说就是“复古”——或者说有点“土”。灰扑扑的按钮、老旧的字体、千篇一律的窗口做出来的程序总带着一股上世纪的“年代感”。对于想快速开发一个既有功能又有颜值的桌面工具或者想给内部工具做个漂亮界面的开发者来说这常常是个痛点。就在这个背景下我遇到了ttkbootstrap。第一次用它把那个经典的Tkinter“Hello World”窗口换了个皮肤效果让我有点惊讶只是加了几行代码那个灰头土脸的窗口瞬间变成了一个拥有现代扁平化设计、协调配色和圆角元素的界面。它不是一个全新的GUI框架而是构建在Tkinter和另一个增强库ttkThemed Tk之上的“主题引擎”和“组件增强包”。你可以把它理解为一套给Tkinter穿的“高级定制西装”让原本其貌不扬的Tkinter程序能轻松拥有接近现代桌面应用甚至是一些Web设计风格的视觉效果。它的核心价值非常直接在不显著增加学习成本和开发复杂度的前提下极大提升Tkinter应用程序的外观和用户体验。你不用去啃Qt、wxPython这类更庞大框架的API也不用自己去折腾复杂的CSS式样式配置ttkbootstrap通过提供一系列预定义的精美主题如darkly,superhero,minty等和增强的、风格一致的Widget组件让美化工作变得像“换皮肤”一样简单。这对于需要快速交付原型、开发内部工具、教学演示或者就是单纯想让自己写的工具“好看点”的Python开发者来说吸引力是巨大的。2. ttkbootstrap的核心机制不只是“换皮”很多人初看ttkbootstrap会觉得它就是个“主题包”换个颜色而已。但实际用下来你会发现它的设计颇有巧思其核心机制可以概括为“继承、增强与主题化”。理解这一点才能用好它而不是仅仅停留在表面。2.1 基于ttk的深度定制Tkinter自带的组件Button, Label等样式能力非常有限。后来引入了ttk模块它用“主题”的概念来管理组件样式分离了样式和逻辑这是一个巨大进步。ttk的组件称为ttk.Widget比原生的Tkinter.Widget更现代支持主题切换。ttkbootstrap并没有另起炉灶而是选择了站在ttk这个“巨人”的肩膀上。它创建了一个自己的Style类通常从ttkbootstrap.Style导入这个类继承并扩展了ttk.Style。ttkbootstrap的所有主题定义都是通过这个Style类来加载和管理的。当你使用style Style(theme‘darkly‘)时它背后做了一系列事情读取内置的darkly主题配置文件这些文件定义了颜色、字体、边框等所有视觉元素将这些配置应用到ttk.Style引擎并注册一系列ttkbootstrap自定义的组件样式。注意这意味着ttkbootstrap的组件在底层依然是ttk.Widget。你的代码逻辑比如事件绑定、数据获取和原来使用ttk.Button、ttk.Entry时是完全一致的。这保证了兼容性和低学习门槛。2.2 预置主题系统与动态切换这是ttkbootstrap最直观的亮点。它内置了数十种精心设计的主题名字都很有特色比如darkly/superhero: 深色系主题适合长时间使用的工具或偏好暗模式的用户。minty/flatly: 浅色、清新风格的主题看起来明亮舒适。cosmo/litera: 偏向博客、文档风格的简洁主题。vapor: 赛博朋克风格非常炫酷。这些主题不仅仅是颜色表它们是一套完整的视觉规范包括了色彩系统定义了主色primary、成功色success、警告色warning、危险色danger、次要色secondary等语义化颜色。这让你可以通过bootstyle“primary“这样的参数来直接应用一套协调的颜色而不是死记硬背#007bff这样的色值。字体与排版统一了字体族和字号使界面文字显示更清晰、现代。组件样式细节包括按钮的圆角半径、输入框的聚焦光环focus highlight、进度条的光滑度、表格的隔行换色等。所有这些细节共同构成了一个主题的“质感”。更强大的是主题可以动态切换。你可以在程序运行时通过style.theme_use(‘new_theme_name‘)来实时更换整个应用程序的皮肤。这个特性对于实现“亮色/暗色模式切换”功能来说简直是零成本。import ttkbootstrap as ttk from ttkbootstrap.constants import * def switch_theme(): # 假设我们只在‘darkly‘和‘minty‘之间切换 current style.theme_use() new_theme ‘minty‘ if current ‘darkly‘ else ‘darkly‘ style.theme_use(new_theme) # 切换后所有使用ttkbootstrap样式的组件会自动更新外观 root ttk.Window(themename“darkly“) style root.style # 获取Style对象 switch_btn ttk.Button(root, text“切换主题“, commandswitch_theme, bootstylePRIMARY) switch_btn.pack(padx10, pady10) root.mainloop()2.3 增强型组件库ttkbootstrap提供了一系列以ttk.为前缀的组件类如ttk.Button,ttk.Entry但它们是被“增强”过的。除了自动继承当前主题的样式很多组件还增加了额外的功能或样式选项。最常用的增强就是bootstyle参数。它是对ttk原生style参数的高度封装和语义化。# 原生ttk你需要定义一个样式名并配置它繁琐且不易维护 style.configure(‘Primary.TButton‘, background‘#007bff‘) btn1 ttk.Button(root, text“原生ttk按钮“, style‘Primary.TButton‘) # ttkbootstrap直接使用语义化参数 btn2 ttk.Button(root, text“主要按钮“, bootstylePRIMARY) # 或 bootstyle“primary“ btn3 ttk.Button(root, text“成功按钮“, bootstyleSUCCESS) btn4 ttk.Button(root, text“危险按钮“, bootstyleDANGER, width20) # 还可以结合其他参数bootstyle的值如PRIMARY,OUTLINE,LINK会映射到当前主题下预定义好的样式类上。例如bootstyle(PRIMARY, OUTLINE)会生成一个主色描边、背景透明的按钮样式。这种设计让样式声明变得极其直观和易于维护。此外ttkbootstrap还额外提供了一些Tkinter/ttk原本没有或很难实现的组件比如Meter: 仪表盘组件用于展示进度或等级。Floodgauge: 另一种风格的进度指示器。DateEntry: 带日历下拉选择的日期输入框。Tableview: 功能更强的表格视图组件基于Treeview增强。这些组件同样深度集成主题系统开箱即用。3. 从零开始一个完整的ttkbootstrap项目实战光说不练假把式。我们通过一个简单的“任务管理工具”来串联ttkbootstrap的核心用法。这个工具将包含主题切换、任务列表的增删改查以及一些典型组件的使用。3.1 环境搭建与基础窗口首先确保已安装ttkbootstrap。它可以通过pip直接安装pip install ttkbootstrap接下来创建主程序文件task_manager.py。import ttkbootstrap as ttk from ttkbootstrap.constants import * from ttkbootstrap.dialogs import Messagebox import json import os class TaskManager: def __init__(self): # 1. 创建主窗口并应用‘darkly‘主题 self.root ttk.Window(title“TTKBootstrap任务管理器“, themename“darkly“, size(800, 600)) self.root.position_center() # 窗口居中显示 # 2. 获取Style对象用于后续主题切换 self.style self.root.style # 3. 任务数据 self.tasks [] self.data_file “tasks.json“ self.load_tasks() # 4. 构建UI self.setup_ui() def setup_ui(self): 构建用户界面 # 顶部控制栏框架 control_frame ttk.Frame(self.root) control_frame.pack(fillX, padx10, pady(10, 5)) # 主题切换下拉框 ttk.Label(control_frame, text“主题:“).pack(sideLEFT, padx(0, 5)) self.theme_var ttk.StringVar(value“darkly“) # ttkbootstrap的Combobox也是增强过的 theme_combo ttk.Combobox( control_frame, textvariableself.theme_var, values[“darkly“, “superhero“, “minty“, “flatly“, “cosmo“, “vapor“], state“readonly“, width15 ) theme_combo.pack(sideLEFT, padx(0, 15)) theme_combo.bind(‘ComboboxSelected‘, self.on_theme_change) # 新增任务输入框和按钮 ttk.Label(control_frame, text“新任务:“).pack(sideLEFT, padx(20, 5)) self.new_task_var ttk.StringVar() task_entry ttk.Entry(control_frame, textvariableself.new_task_var, width30) task_entry.pack(sideLEFT, padx(0, 5)) # 使用OUTLINE风格的按钮更简洁 add_btn ttk.Button( control_frame, text“添加任务“, commandself.add_task, bootstyle(PRIMARY, OUTLINE) ) add_btn.pack(sideLEFT) # 为输入框绑定回车键事件 task_entry.bind(‘Return‘, lambda e: self.add_task()) # 主内容区 - 使用PanedWindow实现可调整分割 main_pane ttk.PanedWindow(self.root, orientHORIZONTAL, bootstyle“default“) main_pane.pack(fillBOTH, expandYES, padx10, pady5) # 左侧任务列表框架 left_frame ttk.Frame(main_pane) main_pane.add(left_frame, weight1) # 任务列表的标题和表格 ttk.Label(left_frame, text“任务列表“, font“-size 11 -weight bold“).pack(anchorW, pady(0, 5)) # 使用Treeview作为任务列表并应用ttkbootstrap样式 columns (“id“, “task“, “status“) self.task_tree ttk.Treeview( left_frame, columnscolumns, show“headings“, # 隐藏默认的树状图标列 bootstyle“default“, height15 ) # 定义列 self.task_tree.heading(“id“, text“ID“) self.task_tree.heading(“task“, text“任务内容“) self.task_tree.heading(“status“, text“状态“) self.task_tree.column(“id“, width50, anchorCENTER) self.task_tree.column(“task“, width300) self.task_tree.column(“status“, width80, anchorCENTER) # 添加滚动条 tree_scroll ttk.Scrollbar(left_frame, orientVERTICAL, commandself.task_tree.yview) self.task_tree.configure(yscrollcommandtree_scroll.set) self.task_tree.pack(sideLEFT, fillBOTH, expandYES) tree_scroll.pack(sideRIGHT, fillY) # 右侧操作面板框架 right_frame ttk.Labelframe(main_pane, text“任务操作“, bootstyleINFO) main_pane.add(right_frame, weight1, minsize250) # 操作按钮 - 使用不同语义色的方块按钮 ttk.Button( right_frame, text“标记为完成“, commandself.mark_as_done, bootstyleSUCCESS, width20 ).pack(pady10) ttk.Button( right_frame, text“标记为待办“, commandself.mark_as_todo, bootstyleWARNING, width20 ).pack(pady10) ttk.Button( right_frame, text“删除选中任务“, commandself.delete_task, bootstyleDANGER, width20 ).pack(pady10) # 状态统计显示 - 使用Meter组件 ttk.Separator(right_frame).pack(fillX, pady20) ttk.Label(right_frame, text“任务完成统计“, font“-size 10“).pack() self.meter ttk.Meter( right_frame, metersize150, padding20, amounttotal100, amountused0, metertype“full“, subtext“完成率“, bootstylePRIMARY ) self.meter.pack(pady10) # 底部状态栏 self.status_var ttk.StringVar(value“就绪 | 任务总数: 0“) status_bar ttk.Label(self.root, textvariableself.status_var, reliefSUNKEN, anchorW) status_bar.pack(sideBOTTOM, fillX, padx10, pady(5, 10)) # 初始化任务列表和统计 self.refresh_task_list() self.update_status() def on_theme_change(self, eventNone): 切换主题事件处理 new_theme self.theme_var.get() self.style.theme_use(new_theme) # 可以在这里添加一些日志 print(f“主题已切换至: {new_theme}“) def load_tasks(self): 从JSON文件加载任务 if os.path.exists(self.data_file): try: with open(self.data_file, ‘r‘, encoding‘utf-8‘) as f: self.tasks json.load(f) except Exception as e: Messagebox.show_error(title“错误“, messagef“加载任务数据失败: {e}“) self.tasks [] else: self.tasks [] def save_tasks(self): 保存任务到JSON文件 try: with open(self.data_file, ‘w‘, encoding‘utf-8‘) as f: json.dump(self.tasks, f, ensure_asciiFalse, indent2) except Exception as e: Messagebox.show_error(title“错误“, messagef“保存任务数据失败: {e}“) def add_task(self): 添加新任务 task_content self.new_task_var.get().strip() if not task_content: Messagebox.show_warning(title“提示“, message“任务内容不能为空“) return new_task { “id“: len(self.tasks) 1, “content“: task_content, “status“: “待办“ # 状态: 待办 / 完成 } self.tasks.append(new_task) self.save_tasks() self.new_task_var.set(““) # 清空输入框 self.refresh_task_list() self.update_status() Messagebox.show_info(title“成功“, message“任务已添加“) def refresh_task_list(self): 刷新Treeview中的任务列表 # 清空现有项 for item in self.task_tree.get_children(): self.task_tree.delete(item) # 插入新数据 for task in self.tasks: # 根据状态决定标签ttkbootstrap的Treeview支持tag tags (“done“,) if task[“status“] “完成“ else (“todo“,) self.task_tree.insert( ““, END, values(task[“id“], task[“content“], task[“status“]), tagstags ) # 配置标签样式例如完成的任务用灰色字体 self.task_tree.tag_configure(“done“, foreground“#6c757d“) # 使用主题中的次要色近似 def get_selected_task_id(self): 获取当前选中任务的ID selection self.task_tree.selection() if not selection: return None selected_item selection[0] item_values self.task_tree.item(selected_item, ‘values‘) return int(item_values[0]) if item_values else None def mark_as_done(self): 标记选中任务为完成 task_id self.get_selected_task_id() if task_id is None: Messagebox.show_warning(title“提示“, message“请先选择一个任务“) return for task in self.tasks: if task[“id“] task_id: task[“status“] “完成“ break self.save_tasks() self.refresh_task_list() self.update_status() def mark_as_todo(self): 标记选中任务为待办 task_id self.get_selected_task_id() if task_id is None: Messagebox.show_warning(title“提示“, message“请先选择一个任务“) return for task in self.tasks: if task[“id“] task_id: task[“status“] “待办“ break self.save_tasks() self.refresh_task_list() self.update_status() def delete_task(self): 删除选中任务 task_id self.get_selected_task_id() if task_id is None: Messagebox.show_warning(title“提示“, message“请先选择一个任务“) return # 使用ttkbootstrap的对话框确认删除 result Messagebox.show_question( title“确认删除“, message“确定要删除这个任务吗此操作不可撤销。“, buttons[“确认:primary“, “取消:secondary“] ) if result “确认“: self.tasks [task for task in self.tasks if task[“id“] ! task_id] # 重新分配ID以保持连续可选 for idx, task in enumerate(self.tasks, start1): task[“id“] idx self.save_tasks() self.refresh_task_list() self.update_status() def update_status(self): 更新底部状态栏和进度仪表盘 total len(self.tasks) done_count sum(1 for task in self.tasks if task[“status“] “完成“) done_percent int((done_count / total * 100)) if total 0 else 0 self.status_var.set(f“就绪 | 任务总数: {total} | 已完成: {done_count}“) # 更新Meter组件 self.meter.configure(amountuseddone_percent) def run(self): 启动主循环 self.root.mainloop() if __name__ “__main__“: app TaskManager() app.run()运行这个程序你会得到一个拥有现代深色界面、支持动态主题切换、具备完整增删改查功能的任务管理器。这个例子几乎用到了ttkbootstrap最核心的特性主题化窗口、语义化按钮、增强的输入框和下拉框、Treeview表格、Meter仪表盘以及风格统一的对话框。4. 深入细节样式定制与高级技巧掌握了基础用法后你可能会遇到一些需要“微调”的场景。ttkbootstrap在提供便捷的同时也保留了足够的定制灵活性。4.1 自定义主题与样式覆盖虽然内置主题丰富但你可能需要匹配公司品牌色或特定设计规范。ttkbootstrap允许你基于现有主题进行微调甚至创建全新的主题。方法一使用Style对象的configure和map方法这是最直接的方式类似于原生的ttk.Style操作但作用在ttkbootstrap的主题之上。import ttkbootstrap as ttk from ttkbootstrap.constants import * root ttk.Window(themename“flatly“) style root.style # 1. 配置一个全新的按钮样式类 style.configure(‘Custom.TButton‘, font(‘Microsoft YaHei‘, 10, ‘bold‘), borderwidth2, relief“ridge“, foreground‘#2c3e50‘, # 文字颜色 background‘#1abc9c‘, # 背景色 focusthickness3, focuscolor‘#1abc9c‘) # 2. 映射状态变化如鼠标悬停、按下 style.map(‘Custom.TButton‘, foreground[(‘pressed‘, ‘#ecf0f1‘), (‘active‘, ‘#34495e‘)], background[(‘pressed‘, ‘#16a085‘), (‘active‘, ‘#1dd2af‘)]) # 使用自定义样式 btn ttk.Button(root, text“自定义按钮“, style‘Custom.TButton‘) btn.pack(padx20, pady20) # 3. 修改所有‘TButton‘的默认圆角影响所有使用该样式的按钮 style.configure(‘TButton‘, borderradius15) # 增大圆角 root.mainloop()方法二创建完整的自定义主题文件高级ttkbootstrap的主题本质上是JSON文件。你可以找到库的安装目录通常在site-packages/ttkbootstrap/themes下复制一个喜欢的主题JSON文件如flatly.json重命名并修改其中的颜色、字体等所有属性然后通过style.load_user_themes(‘你的主题文件夹路径‘)加载最后用style.theme_use(‘你的主题名‘)应用。4.2 布局与容器组件的灵活运用好的UI离不开合理的布局。ttkbootstrap的Frame,Labelframe,PanedWindow等容器组件同样继承了主题样式并且可以结合bootstyle参数获得不同的视觉区块。import ttkbootstrap as ttk from ttkbootstrap.constants import * root ttk.Window(themename“minty“) # 使用不同bootstyle的Labelframe来划分功能区 frame_info ttk.Labelframe(root, text“信息面板“, bootstyleINFO) frame_info.pack(fillX, padx10, pady5) ttk.Label(frame_info, text“这是一个信息提示区域。“).pack(pady5) frame_warning ttk.Labelframe(root, text“警告面板“, bootstyleWARNING) frame_warning.pack(fillX, padx10, pady5) ttk.Label(frame_warning, text“请注意此操作的风险。“).pack(pady5) # 使用网格布局在Frame内进行精细排版 control_frame ttk.Frame(root) control_frame.pack(fillX, padx10, pady10) ttk.Label(control_frame, text“用户名:“).grid(row0, column0, stickyW, padx5, pady5) ttk.Entry(control_frame, width20).grid(row0, column1, padx5, pady5) ttk.Label(control_frame, text“密码:“).grid(row1, column0, stickyW, padx5, pady5) ttk.Entry(control_frame, width20, show“*“).grid(row1, column1, padx5, pady5) # 使用Sticky参数让按钮在网格中右对齐 btn_frame ttk.Frame(control_frame) btn_frame.grid(row2, column0, columnspan2, stickyE, pady10) ttk.Button(btn_frame, text“取消“, bootstyleSECONDARY).pack(sideLEFT, padx5) ttk.Button(btn_frame, text“登录“, bootstylePRIMARY).pack(sideLEFT) root.mainloop()4.3 图标集成与字体图标现代UI离不开图标。ttkbootstrap本身不捆绑图标库但可以轻松集成其他图标字体例如流行的FontAwesome。准备图标字体文件下载FontAwesome的TTF文件如fa-solid-900.ttf。在Tkinter中加载字体使用tkinter.font模块。在标签或按钮上使用将font参数设置为加载的图标字体text参数设置为对应的Unicode字符。import ttkbootstrap as ttk from ttkbootstrap.constants import * import tkinter.font as tkfont root ttk.Window(themename“cosmo“) # 加载字体假设字体文件在当前目录 try: # FontAwesome 6 Free Solid的Unicode示例 (user),  (save),  (times) icon_font tkfont.Font(family“FontAwesome 6 Free Solid“, size12) # 为根窗口添加一个字体引用防止被垃圾回收 root.icon_font icon_font except: print(“未找到图标字体将显示备用文本“) icon_font None # 使用图标的按钮 if icon_font: user_btn ttk.Button(root, text“ 用户“, bootstylePRIMARY, fonticon_font) save_btn ttk.Button(root, text“ 保存“, bootstyleSUCCESS, fonticon_font) else: user_btn ttk.Button(root, text“用户“, bootstylePRIMARY) save_btn ttk.Button(root, text“保存“, bootstyleSUCCESS) user_btn.pack(pady5) save_btn.pack(pady5) root.mainloop()5. 避坑指南与性能考量在实际项目中使用ttkbootstrap我积累了一些经验教训这里分享几个关键点。5.1 组件ID冲突与样式继承的坑ttkbootstrap通过样式类名来应用主题。有时如果你同时使用了原生ttk代码和ttkbootstrap代码或者自己定义了大量样式可能会遇到样式冲突或覆盖不生效的问题。问题现象自定义样式没效果或者某个组件突然变回了默认的“土味”样式。根因分析Tkinter的ttk.Style系统对样式类名有优先级和继承规则。ttkbootstrap在启动时加载主题会配置一系列像‘Primary.TButton‘这样的样式类。如果你之后再用style.configure(‘TButton‘, ...)修改了基类TButton的样式可能会影响所有按钮。反之如果你先自定义了‘Custom.TButton‘但ttkbootstrap的主题加载后没有覆盖它那么它就会保持你的自定义样式。解决方案明确顺序尽量在创建主窗口ttk.Window并获取style对象之后再进行自定义样式配置。确保你的配置在主题加载之后生效。使用更具体的样式类名避免直接修改‘TButton‘这样的通用基类。应该创建像‘MyApp.Primary.TButton‘这样命名空间更具体的样式类减少冲突。利用bootstyle优先使用bootstyle参数让库去处理样式的映射而不是自己手动configure。这是最推荐的做法。5.2 动态主题切换的性能与刷新实时切换主题是一个非常酷的功能但在复杂界面上可能会引起短暂的视觉卡顿或刷新不完全。问题现象切换主题后部分组件特别是自定义绘制的或第三方组件没有立即更新样式。根因分析style.theme_use()会触发Tkinter重新应用样式到所有组件。对于标准ttk组件这通常是即时的。但对于一些复杂组件或者那些样式依赖于代码逻辑动态生成的部件可能需要手动触发更新。解决方案简化界面如果界面非常复杂有成百上千个组件频繁切换主题可能不是好主意。考虑在设置中切换重启应用后生效。手动更新对于自定义组件或特殊部件可以在主题切换后手动调用其configure方法或重新设置其style属性。使用update_idletasks()在切换主题后调用root.update_idletasks()可以强制Tkinter处理所有待处理的刷新事件有时能解决残留样式问题。5.3 打包与分发注意事项当你用PyInstaller,cx_Freeze等工具将ttkbootstrap应用打包成独立exe时可能会遇到主题文件丢失的问题。问题现象打包后的程序运行时报错提示找不到主题文件.json文件。根因分析打包工具默认可能不会包含ttkbootstrap的themes文件夹。解决方案在打包工具的配置文件中如PyInstaller的.spec文件需要显式地将ttkbootstrap/themes目录添加为数据文件。以PyInstaller为例命令行方式pyinstaller --onefile --windowed --add-data “venv/Lib/site-packages/ttkbootstrap/themes;ttkbootstrap/themes“ your_app.py或者修改.spec文件在datas列表中添加datas [(‘venv/Lib/site-packages/ttkbootstrap/themes‘, ‘ttkbootstrap/themes‘)]确保路径venv/Lib/site-packages/ttkbootstrap/themes指向你实际环境中的主题文件夹。5.4 对复杂自定义控件的支持ttkbootstrap主要美化的是ttk系列的标准组件和它自己提供的几个额外组件。如果你在项目中使用了其他复杂的第三方Tkinter控件库比如tkinterweb,customtkinter的部分自定义widgetttkbootstrap可能无法直接为其应用主题。应对策略优先使用ttkbootstrap或ttk组件在项目选型初期就尽量使用受支持的组件。封装与适配对于必须使用的复杂自定义控件可以考虑将其包装在一个ttk.Frame中然后只对框架应用ttkbootstrap样式。或者深入研究该自定义控件的源码看它是否暴露了样式配置接口尝试手动为其配置与当前主题匹配的颜色和字体。接受差异有时让一两个特殊控件保持其原有风格只要不影响整体布局和用户体验也是可以接受的。ttkbootstrap是一个在“快速美化”和“灵活定制”之间取得了很好平衡的库。它可能不是构建最复杂、最专业桌面应用的首选那种场景下PyQt/PySide或甚至Web技术可能是更好的选择但对于绝大多数Python开发者需要快速构建一个美观、实用、可交付的GUI工具的场景来说它是一个能极大提升幸福感和效率的利器。我的体会是下次当你再因为Tkinter的默认界面而不好意思展示你的工具时不妨先花十分钟试试ttkbootstrap它带来的改变可能是立竿见影的。
返回列表