tkdeft 0.2.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. tkdeft-0.4.0/PKG-INFO +206 -0
  2. tkdeft-0.4.0/README.md +176 -0
  3. {tkdeft-0.2.0 → tkdeft-0.4.0}/pyproject.toml +1 -1
  4. tkdeft-0.4.0/tkdeft/__init__.py +180 -0
  5. tkdeft-0.4.0/tkdeft/engines/__init__.py +302 -0
  6. tkdeft-0.4.0/tkdeft/engines/base.py +653 -0
  7. {tkdeft-0.2.0 → tkdeft-0.4.0}/tkdeft/engines/cache.py +72 -10
  8. {tkdeft-0.2.0 → tkdeft-0.4.0}/tkdeft/engines/colors.py +64 -7
  9. {tkdeft-0.2.0 → tkdeft-0.4.0}/tkdeft/engines/pillow_engine.py +3 -1
  10. tkdeft-0.4.0/tkdeft/extra/__init__.py +42 -0
  11. tkdeft-0.4.0/tkdeft/extra/ripple.py +370 -0
  12. tkdeft-0.4.0/tkdeft/object.py +160 -0
  13. {tkdeft-0.2.0 → tkdeft-0.4.0}/tkdeft/svg.py +48 -7
  14. tkdeft-0.4.0/tkdeft/utility/__init__.py +12 -0
  15. tkdeft-0.4.0/tkdeft/utility/fonts.py +58 -0
  16. tkdeft-0.4.0/tkdeft/windows/__init__.py +39 -0
  17. tkdeft-0.4.0/tkdeft/windows/canvas.py +568 -0
  18. tkdeft-0.4.0/tkdeft/windows/draw.py +496 -0
  19. tkdeft-0.4.0/tkdeft/windows/drawwidget.py +217 -0
  20. tkdeft-0.2.0/PKG-INFO +0 -150
  21. tkdeft-0.2.0/README.md +0 -120
  22. tkdeft-0.2.0/tkdeft/__init__.py +0 -32
  23. tkdeft-0.2.0/tkdeft/engines/__init__.py +0 -168
  24. tkdeft-0.2.0/tkdeft/engines/base.py +0 -241
  25. tkdeft-0.2.0/tkdeft/object.py +0 -25
  26. tkdeft-0.2.0/tkdeft/utility/__init__.py +0 -1
  27. tkdeft-0.2.0/tkdeft/utility/fonts.py +0 -20
  28. tkdeft-0.2.0/tkdeft/windows/__init__.py +0 -3
  29. tkdeft-0.2.0/tkdeft/windows/canvas.py +0 -242
  30. tkdeft-0.2.0/tkdeft/windows/draw.py +0 -160
  31. tkdeft-0.2.0/tkdeft/windows/drawwidget.py +0 -120
  32. {tkdeft-0.2.0 → tkdeft-0.4.0}/tkdeft/engines/cairo_engine.py +0 -0
  33. {tkdeft-0.2.0 → tkdeft-0.4.0}/tkdeft/engines/skia_engine.py +0 -0
  34. {tkdeft-0.2.0 → tkdeft-0.4.0}/tkdeft/utility/segoe_font.ttf +0 -0
tkdeft-0.4.0/PKG-INFO ADDED
@@ -0,0 +1,206 @@
1
+ Metadata-Version: 2.4
2
+ Name: tkdeft
3
+ Version: 0.4.0
4
+ Summary: 使用tkinter+tksvg开发的现代化界面库
5
+ Author: XiangQinxi
6
+ Author-email: xiangqinxi@outlook.com
7
+ Requires-Python: >=3.7,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.7
10
+ Classifier: Programming Language :: Python :: 3.8
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Provides-Extra: cairo
18
+ Provides-Extra: raster
19
+ Provides-Extra: skia
20
+ Requires-Dist: easydict (>=1.13,<2.0)
21
+ Requires-Dist: numpy
22
+ Requires-Dist: pillow (>=10.2)
23
+ Requires-Dist: pycairo (>=1.29,<2.0) ; extra == "cairo" or extra == "raster"
24
+ Requires-Dist: skia-python (>=138.0,<139.0) ; extra == "skia" or extra == "raster"
25
+ Requires-Dist: svgwrite (>=1.4.3,<2.0.0)
26
+ Requires-Dist: tkextrafont (>=0.6.3,<0.7.0)
27
+ Requires-Dist: tksvg (>=0.7.4,<0.8.0)
28
+ Project-URL: Documentation, https://tkdeft.netlify.app
29
+ Description-Content-Type: text/markdown
30
+
31
+ <div align="center">
32
+
33
+ # tkdeft
34
+
35
+ </div>
36
+
37
+ [![Netlify Status](https://api.netlify.com/api/v1/badges/c7626ce2-9556-4e4f-b28e-36dc0b513398/deploy-status)](https://app.netlify.com/sites/tkdeft/deploys)
38
+
39
+ 意为`灵巧`,灵活轻巧好用
40
+
41
+ 一句话:**把矢量绘图变成 Tkinter 控件的底座。**
42
+
43
+ > 开发中
44
+
45
+ ---
46
+
47
+ ## 注意
48
+
49
+ > [!NOTE]
50
+ > 这里呢,已经成为[tkfluent](https://pypi.org/project/tkfluent)的基础库了,不含[tkfluent](https://pypi.org/project/tkfluent)的组件。
51
+ > 如果你想体验扩展界面库的效果,请去[tkfluent](https://pypi.org/project/tkfluent)查阅。
52
+
53
+ 用这套零件搭出来的组件库长这样([tkfluent](https://pypi.org/project/tkfluent)):
54
+
55
+ | 浅色 | 深色 |
56
+ | --- | --- |
57
+ | ![浅色](docs/docs/assets/gallery-light.png) | ![深色](docs/docs/assets/gallery-dark.png) |
58
+
59
+ ## 原理
60
+
61
+ 一句话:**先用矢量绘图生成图片,再交给 `Canvas` / `Label` 显示出来。**
62
+
63
+ 具体走哪条路是可切换的:
64
+
65
+ | 方式 | 过程 |
66
+ | --- | --- |
67
+ | SVG 引擎(默认 `tksvg`) | `svgwrite` 生成 SVG → 写临时文件 → `tksvg` 读回来栅格化 |
68
+ | 栅格引擎(`skia` / `pillow` / `cairo`) | 进程内直接画到位图,**完全不碰磁盘** |
69
+
70
+ > 这其中还是有些坑的(比如图片不显示——那其实是 `PhotoImage` 被垃圾回收导致的),
71
+ > 完整清单见文档站的[常见问题与排查](docs/docs/usage/faq.md)。
72
+
73
+ ## 快速上手
74
+
75
+ ```bash
76
+ pip install -U tkdeft
77
+ ```
78
+
79
+ ```python
80
+ import tkinter
81
+
82
+ from tkdeft.windows.canvas import DCanvas
83
+
84
+ root = tkinter.Tk()
85
+ canvas = DCanvas(root, width=240, height=120, background="#f3f3f3")
86
+ canvas.pack()
87
+
88
+ # 一行画图元:栅格引擎走进程内快速路径,否则自动回退 SVG
89
+ canvas.draw_roundrect(20, 20, 200, 76, 8,
90
+ fill="#ffffff", outline="#000000", outline_opacity=0.25)
91
+
92
+ root.mainloop()
93
+ ```
94
+
95
+ 完整文档(安装 / 快速上手 / 概念与架构 / 指南 / API):
96
+ <https://tkdeft.netlify.app>
97
+
98
+ `tkdeft.extra` 里放可以直接用的功能,不是成品控件。目前有一个
99
+ [Material 涟漪效果](tkdeft/extra/ripple.py):给任意控件加一层从按下处扩散的半透明涟漪,
100
+ 圆角裁剪、抗锯齿、按时间算进度都处理好,你的按钮长什么样它不管。
101
+
102
+ ```python
103
+ from tkdeft.extra.ripple import Ripple
104
+
105
+ self.ripple = Ripple(self, on_frame=self._paint) # ① 建控制器,每帧回调你重绘
106
+ self.ripple.start(event.x, event.y) # ② 点击处起涟漪
107
+ self.ripple.paint(color="#000000", opacity=0.12, # ③ 在重绘里贴一层
108
+ corner_radius=8)
109
+ ```
110
+
111
+ 仓库里的 `examples/ripple_button.py` 是接法演示:圆角按钮、悬停/按压/焦点/禁用、
112
+ `T` 换主题都由示例自己画,涟漪只借 `tkdeft.extra.ripple`;它同时带一个非交互自检:
113
+
114
+ ```bash
115
+ python examples/ripple_button.py # 自动挑栅格引擎(skia > cairo > pillow)
116
+ python examples/ripple_button.py --check # 只跑自检,不开窗口
117
+ ```
118
+
119
+ 写法讲解见文档站的
120
+ [涟漪按钮:可直接用的成品控件](https://tkdeft.netlify.app/usage/ripple-button)。
121
+
122
+ ## 绘制引擎
123
+
124
+ `tkdeft` 把"**画什么**"和"**用什么画**"分开了。组件只需要描述一个
125
+ `RoundRectSpec`(尺寸、圆角、填充、描边……),具体由哪个引擎栅格化是可切换的。
126
+
127
+ 同一份规格交给 5 个引擎:
128
+
129
+ ![engine compare](docs/docs/assets/engines-compare.png)
130
+
131
+ ```python
132
+ from tkdeft.engines import set_engine, list_engines, describe_engines, cache_stats
133
+
134
+ print(list_engines()) # {'tksvg': True, 'wand': True, 'skia': True, ...}
135
+ set_engine("skia") # 或 set_engine(2)
136
+ print(cache_stats()) # 缓存命中率,便于诊断
137
+ ```
138
+
139
+ | 编号 | 引擎 | 类型 | 说明 | 额外依赖 |
140
+ | --- | --- | --- | --- | --- |
141
+ | 0 | `tksvg` | SVG | 默认,保持既有行为 | 无 |
142
+ | 1 | `wand` | SVG | 经 Wand(ImageMagick) 转 PNG | `Wand` |
143
+ | 2 | `skia` | 栅格 | skia-python,进程内出图,画质与速度最好 | `pip install tkdeft[skia]` |
144
+ | 3 | `pillow` | 栅格 | Pillow 超采样,**永远可用** | 无(Pillow 是硬依赖) |
145
+ | 4 | `cairo` | 栅格 | pycairo | `pip install tkdeft[cairo]` |
146
+
147
+ 栅格引擎不写临时文件、不解析 SVG、不碰磁盘;渲染结果按规格缓存,
148
+ **同尺寸同配色的一组控件共用同一张图片**。
149
+
150
+ ### 实测(120×32 圆角矩形,本机)
151
+
152
+ ![perf](docs/docs/assets/perf-bars.png)
153
+
154
+ | 场景 | 优化前 | 仅修基础设施 | + skia 引擎 |
155
+ | --- | --- | --- | --- |
156
+ | 圆角矩形(尺寸各异) | 13.81 ms | 4.94 ms | **1.26 ms** |
157
+ | 圆角矩形(参数相同) | 10.80 ms | 4.33 ms | **0.02 ms** |
158
+ | 按钮重绘 | 5.95 ms | 2.86 ms | **0.15 ms** |
159
+ | 按钮 hover 往返 | 13.65 ms | 6.08 ms | **0.26 ms** |
160
+ | 20 个按钮批量重绘 | 139.9 ms | 110.4 ms | **2.93 ms** |
161
+
162
+ 复现:`python benchmarks/run_all.py`(9 项回归 + 性能基准,详见
163
+ [回归与性能](docs/docs/usage/benchmarks.md))
164
+
165
+ ## 已修复的缺陷
166
+
167
+ 这一轮审查中定位并修掉的真实问题(都不是"风格问题"):
168
+
169
+ | 问题 | 影响 |
170
+ | --- | --- |
171
+ | `DSvgDraw.temppath()` 每次调用都 `mkstemp()` 且**从不关闭返回的 fd** | 每绘制一帧泄漏一个句柄,并在临时目录留下一个残留文件 |
172
+ | `DDrawWidget.__init__` 一次性 `mkstemp()` 四个临时文件 | 每个控件创建即泄漏 4 个句柄(20 个按钮 = 80 个) |
173
+ | `DCanvas.create_round_rectangle` 只把图片存进 `self._img` / `self._tkimg` | 同一画布上多张图片时,除最后一张外都会被 GC,**画布 item 变空白** |
174
+ | `RenderManager._render_all` 调用 `widget.winfo_zorder()` | `tkinter` **没有**这个方法,只要有脏控件就抛 `AttributeError` |
175
+ | `RenderManager._schedule_render` 里 `tk._default_root or list(...)[0]` | 两者都不可用时 `IndexError` |
176
+ | `_draw` 结尾又 `mark_dirty(self)` | 集中式调度下同一控件被重绘两遍 |
177
+ | svgwrite 生成的矩形用 `translate(0.5,0.5)` + 整宽整高 | 描边中心线压在画布边界上,**外侧半个线宽被裁掉** |
178
+ | `create_svg_image` 对 `way` 未做兜底 | 回退路径遇到非 0/1 的渲染器编号会直接失败 |
179
+ | `tkdeft.svg` 把 `None` / `"transparent"` 直接交给 svgwrite | 栅格引擎认这两者,svgwrite 只认 `"none"` → 同一份规格换了引擎就 `TypeError` |
180
+
181
+ ## 计划
182
+
183
+ 未来我打算先制作出`SunValley`设计的库然后就去做别的项目,[tkfluent](https://pypi.org/project/tkfluent)
184
+
185
+ 至于完整文档,我后面会加紧制作的。
186
+
187
+ 设计来源: https://pixso.cn/community/file/ItC5JH1TOwj15EeOPcY7LQ?from_share
188
+
189
+ ### 为什么不像tkadw一样做跟易用的主题?
190
+
191
+ 因为`svg`能实现很多漂亮的组件,而我套的模板可能不对其它设计起太大的作用
192
+
193
+ 所以我将这个设计库放在这里当做模板,供其它设计者参考使用。
194
+
195
+ ## 更新日志
196
+
197
+ 版本变更统一记录在文档站的[更新日志](https://tkdeft.netlify.app/blog/)里
198
+ (源文件在 `docs/docs/blog/posts/`),按时间倒序排列:
199
+
200
+ | 版本 | 一句话 | 发布说明 |
201
+ | --- | --- | --- |
202
+ | `0.4.0` | 新增 `tkdeft.extra`:可复用的 Material 涟漪效果(控制器 + 纯函数) | [2026-10-18](docs/docs/blog/posts/2026-10-18-release.md) |
203
+ | `0.3.0` | 把对外接口补齐:统一绘制入口、引擎查询、`DObject` 补全 | [2026-09-13](docs/docs/blog/posts/2026-09-13.md) |
204
+ | `0.2.0` | 可插拔绘制引擎层 + 进程内栅格引擎 + 规格缓存 | [2026-09-12](docs/docs/blog/posts/2026-09-12.md) |
205
+ | `0.1.0` | 完善功能 | [2025-06-26](docs/docs/blog/posts/2025-06-26.md) |
206
+ | 更早 | `0.0.1` – `0.0.9` 的起步阶段 | [回顾](docs/docs/blog/posts/2024-01-26.md) |
tkdeft-0.4.0/README.md ADDED
@@ -0,0 +1,176 @@
1
+ <div align="center">
2
+
3
+ # tkdeft
4
+
5
+ </div>
6
+
7
+ [![Netlify Status](https://api.netlify.com/api/v1/badges/c7626ce2-9556-4e4f-b28e-36dc0b513398/deploy-status)](https://app.netlify.com/sites/tkdeft/deploys)
8
+
9
+ 意为`灵巧`,灵活轻巧好用
10
+
11
+ 一句话:**把矢量绘图变成 Tkinter 控件的底座。**
12
+
13
+ > 开发中
14
+
15
+ ---
16
+
17
+ ## 注意
18
+
19
+ > [!NOTE]
20
+ > 这里呢,已经成为[tkfluent](https://pypi.org/project/tkfluent)的基础库了,不含[tkfluent](https://pypi.org/project/tkfluent)的组件。
21
+ > 如果你想体验扩展界面库的效果,请去[tkfluent](https://pypi.org/project/tkfluent)查阅。
22
+
23
+ 用这套零件搭出来的组件库长这样([tkfluent](https://pypi.org/project/tkfluent)):
24
+
25
+ | 浅色 | 深色 |
26
+ | --- | --- |
27
+ | ![浅色](docs/docs/assets/gallery-light.png) | ![深色](docs/docs/assets/gallery-dark.png) |
28
+
29
+ ## 原理
30
+
31
+ 一句话:**先用矢量绘图生成图片,再交给 `Canvas` / `Label` 显示出来。**
32
+
33
+ 具体走哪条路是可切换的:
34
+
35
+ | 方式 | 过程 |
36
+ | --- | --- |
37
+ | SVG 引擎(默认 `tksvg`) | `svgwrite` 生成 SVG → 写临时文件 → `tksvg` 读回来栅格化 |
38
+ | 栅格引擎(`skia` / `pillow` / `cairo`) | 进程内直接画到位图,**完全不碰磁盘** |
39
+
40
+ > 这其中还是有些坑的(比如图片不显示——那其实是 `PhotoImage` 被垃圾回收导致的),
41
+ > 完整清单见文档站的[常见问题与排查](docs/docs/usage/faq.md)。
42
+
43
+ ## 快速上手
44
+
45
+ ```bash
46
+ pip install -U tkdeft
47
+ ```
48
+
49
+ ```python
50
+ import tkinter
51
+
52
+ from tkdeft.windows.canvas import DCanvas
53
+
54
+ root = tkinter.Tk()
55
+ canvas = DCanvas(root, width=240, height=120, background="#f3f3f3")
56
+ canvas.pack()
57
+
58
+ # 一行画图元:栅格引擎走进程内快速路径,否则自动回退 SVG
59
+ canvas.draw_roundrect(20, 20, 200, 76, 8,
60
+ fill="#ffffff", outline="#000000", outline_opacity=0.25)
61
+
62
+ root.mainloop()
63
+ ```
64
+
65
+ 完整文档(安装 / 快速上手 / 概念与架构 / 指南 / API):
66
+ <https://tkdeft.netlify.app>
67
+
68
+ `tkdeft.extra` 里放可以直接用的功能,不是成品控件。目前有一个
69
+ [Material 涟漪效果](tkdeft/extra/ripple.py):给任意控件加一层从按下处扩散的半透明涟漪,
70
+ 圆角裁剪、抗锯齿、按时间算进度都处理好,你的按钮长什么样它不管。
71
+
72
+ ```python
73
+ from tkdeft.extra.ripple import Ripple
74
+
75
+ self.ripple = Ripple(self, on_frame=self._paint) # ① 建控制器,每帧回调你重绘
76
+ self.ripple.start(event.x, event.y) # ② 点击处起涟漪
77
+ self.ripple.paint(color="#000000", opacity=0.12, # ③ 在重绘里贴一层
78
+ corner_radius=8)
79
+ ```
80
+
81
+ 仓库里的 `examples/ripple_button.py` 是接法演示:圆角按钮、悬停/按压/焦点/禁用、
82
+ `T` 换主题都由示例自己画,涟漪只借 `tkdeft.extra.ripple`;它同时带一个非交互自检:
83
+
84
+ ```bash
85
+ python examples/ripple_button.py # 自动挑栅格引擎(skia > cairo > pillow)
86
+ python examples/ripple_button.py --check # 只跑自检,不开窗口
87
+ ```
88
+
89
+ 写法讲解见文档站的
90
+ [涟漪按钮:可直接用的成品控件](https://tkdeft.netlify.app/usage/ripple-button)。
91
+
92
+ ## 绘制引擎
93
+
94
+ `tkdeft` 把"**画什么**"和"**用什么画**"分开了。组件只需要描述一个
95
+ `RoundRectSpec`(尺寸、圆角、填充、描边……),具体由哪个引擎栅格化是可切换的。
96
+
97
+ 同一份规格交给 5 个引擎:
98
+
99
+ ![engine compare](docs/docs/assets/engines-compare.png)
100
+
101
+ ```python
102
+ from tkdeft.engines import set_engine, list_engines, describe_engines, cache_stats
103
+
104
+ print(list_engines()) # {'tksvg': True, 'wand': True, 'skia': True, ...}
105
+ set_engine("skia") # 或 set_engine(2)
106
+ print(cache_stats()) # 缓存命中率,便于诊断
107
+ ```
108
+
109
+ | 编号 | 引擎 | 类型 | 说明 | 额外依赖 |
110
+ | --- | --- | --- | --- | --- |
111
+ | 0 | `tksvg` | SVG | 默认,保持既有行为 | 无 |
112
+ | 1 | `wand` | SVG | 经 Wand(ImageMagick) 转 PNG | `Wand` |
113
+ | 2 | `skia` | 栅格 | skia-python,进程内出图,画质与速度最好 | `pip install tkdeft[skia]` |
114
+ | 3 | `pillow` | 栅格 | Pillow 超采样,**永远可用** | 无(Pillow 是硬依赖) |
115
+ | 4 | `cairo` | 栅格 | pycairo | `pip install tkdeft[cairo]` |
116
+
117
+ 栅格引擎不写临时文件、不解析 SVG、不碰磁盘;渲染结果按规格缓存,
118
+ **同尺寸同配色的一组控件共用同一张图片**。
119
+
120
+ ### 实测(120×32 圆角矩形,本机)
121
+
122
+ ![perf](docs/docs/assets/perf-bars.png)
123
+
124
+ | 场景 | 优化前 | 仅修基础设施 | + skia 引擎 |
125
+ | --- | --- | --- | --- |
126
+ | 圆角矩形(尺寸各异) | 13.81 ms | 4.94 ms | **1.26 ms** |
127
+ | 圆角矩形(参数相同) | 10.80 ms | 4.33 ms | **0.02 ms** |
128
+ | 按钮重绘 | 5.95 ms | 2.86 ms | **0.15 ms** |
129
+ | 按钮 hover 往返 | 13.65 ms | 6.08 ms | **0.26 ms** |
130
+ | 20 个按钮批量重绘 | 139.9 ms | 110.4 ms | **2.93 ms** |
131
+
132
+ 复现:`python benchmarks/run_all.py`(9 项回归 + 性能基准,详见
133
+ [回归与性能](docs/docs/usage/benchmarks.md))
134
+
135
+ ## 已修复的缺陷
136
+
137
+ 这一轮审查中定位并修掉的真实问题(都不是"风格问题"):
138
+
139
+ | 问题 | 影响 |
140
+ | --- | --- |
141
+ | `DSvgDraw.temppath()` 每次调用都 `mkstemp()` 且**从不关闭返回的 fd** | 每绘制一帧泄漏一个句柄,并在临时目录留下一个残留文件 |
142
+ | `DDrawWidget.__init__` 一次性 `mkstemp()` 四个临时文件 | 每个控件创建即泄漏 4 个句柄(20 个按钮 = 80 个) |
143
+ | `DCanvas.create_round_rectangle` 只把图片存进 `self._img` / `self._tkimg` | 同一画布上多张图片时,除最后一张外都会被 GC,**画布 item 变空白** |
144
+ | `RenderManager._render_all` 调用 `widget.winfo_zorder()` | `tkinter` **没有**这个方法,只要有脏控件就抛 `AttributeError` |
145
+ | `RenderManager._schedule_render` 里 `tk._default_root or list(...)[0]` | 两者都不可用时 `IndexError` |
146
+ | `_draw` 结尾又 `mark_dirty(self)` | 集中式调度下同一控件被重绘两遍 |
147
+ | svgwrite 生成的矩形用 `translate(0.5,0.5)` + 整宽整高 | 描边中心线压在画布边界上,**外侧半个线宽被裁掉** |
148
+ | `create_svg_image` 对 `way` 未做兜底 | 回退路径遇到非 0/1 的渲染器编号会直接失败 |
149
+ | `tkdeft.svg` 把 `None` / `"transparent"` 直接交给 svgwrite | 栅格引擎认这两者,svgwrite 只认 `"none"` → 同一份规格换了引擎就 `TypeError` |
150
+
151
+ ## 计划
152
+
153
+ 未来我打算先制作出`SunValley`设计的库然后就去做别的项目,[tkfluent](https://pypi.org/project/tkfluent)
154
+
155
+ 至于完整文档,我后面会加紧制作的。
156
+
157
+ 设计来源: https://pixso.cn/community/file/ItC5JH1TOwj15EeOPcY7LQ?from_share
158
+
159
+ ### 为什么不像tkadw一样做跟易用的主题?
160
+
161
+ 因为`svg`能实现很多漂亮的组件,而我套的模板可能不对其它设计起太大的作用
162
+
163
+ 所以我将这个设计库放在这里当做模板,供其它设计者参考使用。
164
+
165
+ ## 更新日志
166
+
167
+ 版本变更统一记录在文档站的[更新日志](https://tkdeft.netlify.app/blog/)里
168
+ (源文件在 `docs/docs/blog/posts/`),按时间倒序排列:
169
+
170
+ | 版本 | 一句话 | 发布说明 |
171
+ | --- | --- | --- |
172
+ | `0.4.0` | 新增 `tkdeft.extra`:可复用的 Material 涟漪效果(控制器 + 纯函数) | [2026-10-18](docs/docs/blog/posts/2026-10-18-release.md) |
173
+ | `0.3.0` | 把对外接口补齐:统一绘制入口、引擎查询、`DObject` 补全 | [2026-09-13](docs/docs/blog/posts/2026-09-13.md) |
174
+ | `0.2.0` | 可插拔绘制引擎层 + 进程内栅格引擎 + 规格缓存 | [2026-09-12](docs/docs/blog/posts/2026-09-12.md) |
175
+ | `0.1.0` | 完善功能 | [2025-06-26](docs/docs/blog/posts/2025-06-26.md) |
176
+ | 更早 | `0.0.1` – `0.0.9` 的起步阶段 | [回顾](docs/docs/blog/posts/2024-01-26.md) |
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "tkdeft"
3
- version = "0.2.0"
3
+ version = "0.4.0"
4
4
  description = "使用tkinter+tksvg开发的现代化界面库"
5
5
  authors = ["XiangQinxi <xiangqinxi@outlook.com>"]
6
6
  readme = "README.md"
@@ -0,0 +1,180 @@
1
+ """tkdeft —— 把矢量绘图变成 Tkinter 控件的底座。
2
+
3
+ 本包不提供具体组件,只提供零件:
4
+
5
+ * :mod:`tkdeft.engines` —— 可插拔的绘制引擎(tksvg / wand / skia / pillow / cairo)
6
+ * :mod:`tkdeft.svg` —— SVG 形状助手(统一的圆角矩形几何)
7
+ * :mod:`tkdeft.windows` —— ``DCanvas`` / ``DDraw`` / ``DSvgDraw`` / ``DDrawWidget``
8
+ * :mod:`tkdeft.object` —— ``DObject`` 配置容器
9
+ * :mod:`tkdeft.utility` —— 字体等零碎工具
10
+ * :mod:`tkdeft.extra` —— 可选的附加功能(目前是 Material 涟漪效果)
11
+
12
+ 最常用的东西都从顶层再导出一份,所以下面两种写法等价::
13
+
14
+ from tkdeft.engines import RoundRectSpec, set_engine, render_roundrect
15
+ from tkdeft import RoundRectSpec, set_engine, render_roundrect
16
+
17
+ 快速上手
18
+ --------
19
+ ::
20
+
21
+ import tkinter
22
+ from tkdeft import DCanvas, RoundRectSpec, set_engine
23
+
24
+ set_engine("skia") # 换成进程内栅格引擎(可选)
25
+
26
+ root = tkinter.Tk()
27
+ canvas = DCanvas(root, width=200, height=100)
28
+ canvas.pack()
29
+ canvas.draw_roundrect(0, 0, 120, 32, 6, fill="#ffffff", outline="#000000")
30
+ root.mainloop()
31
+
32
+ 想直接要一张图片(不起窗口)::
33
+
34
+ photo = render_roundrect(
35
+ RoundRectSpec(width=120, height=32, rx=6, fill="#ffffff"),
36
+ master=canvas,
37
+ )
38
+
39
+ 能力探测
40
+ --------
41
+ 旧版本没有 :mod:`tkdeft.engines` 子包,因此依赖方用 :data:`HAS_ENGINES`
42
+ 做能力探测,比解析版本号更直接::
43
+
44
+ import tkdeft
45
+
46
+ if getattr(tkdeft, "HAS_ENGINES", False):
47
+ from tkdeft.engines import set_engine
48
+
49
+ 附加功能
50
+ --------
51
+ :mod:`tkdeft.extra` 里是可以直接拿去用的小功能,它按需加载(用到时才 import
52
+ Pillow 的 ``ImageTk``)::
53
+
54
+ from tkdeft.extra.ripple import Ripple
55
+ from tkdeft import extra # 等价,懒加载整个子包
56
+ """
57
+
58
+ from __future__ import annotations
59
+
60
+ import importlib
61
+
62
+ from . import engines, svg, utility, windows
63
+ from .engines import (
64
+ DEFAULT_ENGINE_NAME,
65
+ RENDERER_INDEX,
66
+ DrawEngine,
67
+ RoundRectSpec,
68
+ SvgEngine,
69
+ ThumbSpec,
70
+ TrackSpec,
71
+ UnknownEngineError,
72
+ available_engines,
73
+ cache_stats,
74
+ clear_cache,
75
+ describe_engines,
76
+ get_cache,
77
+ get_engine,
78
+ get_engine_name,
79
+ list_engines,
80
+ register_engine,
81
+ render,
82
+ render_roundrect,
83
+ render_thumb,
84
+ render_track,
85
+ reset_engine,
86
+ set_cache_budget,
87
+ set_engine,
88
+ )
89
+ from .object import DObject
90
+ from .svg import add_roundrect, roundrect_geometry
91
+ from .utility import SEGOE_FONT_FILE, SegoeFont, segoe_font, segue_font_file
92
+ from .windows import (
93
+ DCanvas,
94
+ DDraw,
95
+ DDrawWidget,
96
+ DDrawWidgetCanvas,
97
+ DDrawWidgetDraw,
98
+ DSvgDraw,
99
+ )
100
+
101
+ #: 版本号。tkfluent 会据此判断环境里的 tkdeft 是否够新。
102
+ #: 注意:需要与 pyproject.toml 里的 version 保持一致。
103
+ __version__ = "0.4.0"
104
+
105
+ #: :data:`__version__` 的数字形式,便于比较:``(0, 4, 0)``
106
+ __version_info__ = tuple(int(part) for part in __version__.split(".") if part.isdigit())
107
+
108
+ #: 是否提供绘制引擎层(tkfluent >= 0.2.0 依赖它)。
109
+ #: 旧版本没有这个子包,用它做能力探测比解析版本号更直接。
110
+ HAS_ENGINES = True
111
+
112
+
113
+ def __getattr__(name: str):
114
+ """按需加载 :mod:`tkdeft.extra`。
115
+
116
+ ``import tkdeft`` 不应该顺带把 Pillow 的 ``ImageTk`` 和附加功能拉进来,
117
+ 所以这里只在真的用到时再导入::
118
+
119
+ from tkdeft import extra # 触发 __getattr__
120
+ """
121
+ if name == "extra":
122
+ # 用 import_module 而不是 ``from . import extra``:后者会走
123
+ # ``_handle_fromlist`` → ``getattr(self, "extra")`` → 又回到本函数,无限递归。
124
+ return importlib.import_module(".extra", __name__)
125
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
126
+
127
+
128
+ __all__ = [
129
+ # 子包
130
+ "engines",
131
+ "svg",
132
+ "utility",
133
+ "windows",
134
+ "extra",
135
+ # 版本与能力探测
136
+ "__version__",
137
+ "__version_info__",
138
+ "HAS_ENGINES",
139
+ # 基础
140
+ "DObject",
141
+ # 画布与绘制后端
142
+ "DCanvas",
143
+ "DDraw",
144
+ "DSvgDraw",
145
+ "DDrawWidget",
146
+ "DDrawWidgetCanvas",
147
+ "DDrawWidgetDraw",
148
+ "add_roundrect",
149
+ "roundrect_geometry",
150
+ # 字体
151
+ "SegoeFont",
152
+ "segue_font_file",
153
+ "SEGOE_FONT_FILE",
154
+ "segoe_font",
155
+ # 绘制引擎
156
+ "DrawEngine",
157
+ "SvgEngine",
158
+ "RoundRectSpec",
159
+ "TrackSpec",
160
+ "ThumbSpec",
161
+ "UnknownEngineError",
162
+ "RENDERER_INDEX",
163
+ "DEFAULT_ENGINE_NAME",
164
+ "register_engine",
165
+ "get_engine",
166
+ "get_engine_name",
167
+ "set_engine",
168
+ "reset_engine",
169
+ "list_engines",
170
+ "available_engines",
171
+ "describe_engines",
172
+ "render",
173
+ "render_roundrect",
174
+ "render_track",
175
+ "render_thumb",
176
+ "get_cache",
177
+ "clear_cache",
178
+ "cache_stats",
179
+ "set_cache_budget",
180
+ ]