ctk-kit 0.1.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.
- ctk_kit-0.1.0/LICENSE +21 -0
- ctk_kit-0.1.0/PKG-INFO +204 -0
- ctk_kit-0.1.0/README.md +170 -0
- ctk_kit-0.1.0/ctk_kit/__init__.py +88 -0
- ctk_kit-0.1.0/ctk_kit/buttons.py +233 -0
- ctk_kit-0.1.0/ctk_kit/dropdown.py +264 -0
- ctk_kit-0.1.0/ctk_kit/inputs.py +160 -0
- ctk_kit-0.1.0/ctk_kit/layout.py +194 -0
- ctk_kit-0.1.0/ctk_kit/py.typed +0 -0
- ctk_kit-0.1.0/ctk_kit/scroll_list.py +332 -0
- ctk_kit-0.1.0/ctk_kit/theme.py +72 -0
- ctk_kit-0.1.0/ctk_kit/tokens.py +86 -0
- ctk_kit-0.1.0/ctk_kit.egg-info/PKG-INFO +204 -0
- ctk_kit-0.1.0/ctk_kit.egg-info/SOURCES.txt +26 -0
- ctk_kit-0.1.0/ctk_kit.egg-info/dependency_links.txt +1 -0
- ctk_kit-0.1.0/ctk_kit.egg-info/requires.txt +4 -0
- ctk_kit-0.1.0/ctk_kit.egg-info/top_level.txt +1 -0
- ctk_kit-0.1.0/pyproject.toml +59 -0
- ctk_kit-0.1.0/setup.cfg +4 -0
- ctk_kit-0.1.0/tests/test_buttons.py +145 -0
- ctk_kit-0.1.0/tests/test_dropdown.py +140 -0
- ctk_kit-0.1.0/tests/test_inputs.py +126 -0
- ctk_kit-0.1.0/tests/test_layout.py +133 -0
- ctk_kit-0.1.0/tests/test_package.py +94 -0
- ctk_kit-0.1.0/tests/test_scroll_list.py +193 -0
- ctk_kit-0.1.0/tests/test_showcase.py +428 -0
- ctk_kit-0.1.0/tests/test_theme.py +86 -0
- ctk_kit-0.1.0/tests/test_tokens.py +94 -0
ctk_kit-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 加点盐
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ctk_kit-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ctk-kit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: 面向 CustomTkinter 的轻量界面基件:深浅色令牌、常用控件与懒加载列表
|
|
5
|
+
Author-email: 加点盐 <1431705288@qq.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://gitee.com/kuangjianke/ctk-kit
|
|
8
|
+
Project-URL: Repository, https://gitee.com/kuangjianke/ctk-kit
|
|
9
|
+
Project-URL: Issues, https://gitee.com/kuangjianke/ctk-kit/issues
|
|
10
|
+
Project-URL: Changelog, https://gitee.com/kuangjianke/ctk-kit/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: GitHub Mirror, https://github.com/DashSalter/ctk-kit
|
|
12
|
+
Keywords: customtkinter,tkinter,ui,ui-kit,theme,dark-mode,widgets
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
26
|
+
Classifier: Typing :: Typed
|
|
27
|
+
Requires-Python: >=3.8
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: customtkinter>=5.2
|
|
31
|
+
Provides-Extra: test
|
|
32
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# ctk-kit
|
|
36
|
+
|
|
37
|
+
[](https://github.com/DashSalter/ctk-kit/actions/workflows/ci.yml)
|
|
38
|
+
[](https://pypi.org/project/ctk-kit/)
|
|
39
|
+
[](https://pypi.org/project/ctk-kit/)
|
|
40
|
+
[](LICENSE)
|
|
41
|
+
|
|
42
|
+
面向 [CustomTkinter](https://github.com/TomSchimansky/CustomTkinter) 的轻量界面基件:
|
|
43
|
+
一套深浅色设计令牌、一批常用控件,以及一个会自动分页的懒加载列表。
|
|
44
|
+
支持 Python 3.8 – 3.14。
|
|
45
|
+
|
|
46
|
+
写它的起因很朴素——每个 customtkinter 项目都要重新调一遍颜色、圆角、按钮宽度和滚动列表的
|
|
47
|
+
分批渲染,调完还很难看齐。ctk-kit 把这些收成一层薄薄的公共件,项目之间可以直接复用。
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
pip install ctk-kit
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import customtkinter as ctk
|
|
55
|
+
from ctk_kit import apply_appearance, primary_button, page_header
|
|
56
|
+
|
|
57
|
+
apply_appearance("Dark")
|
|
58
|
+
app = ctk.CTk()
|
|
59
|
+
|
|
60
|
+
head, info = page_header(app, "全部记录")
|
|
61
|
+
head.pack(fill="x", padx=20, pady=(16, 8))
|
|
62
|
+
primary_button(app, "新建", lambda: None).pack()
|
|
63
|
+
app.mainloop()
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
看实际效果:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
git clone https://gitee.com/kuangjianke/ctk-kit
|
|
70
|
+
cd ctk-kit
|
|
71
|
+
python examples/showcase.py
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
展示程序有八个页面:总览、基件、按钮、输入、布局、列表、主题、表单,把每个公开构建都用一遍。
|
|
75
|
+
基件页把 24 个色值连同浅/深两套十六进制值一起列出来,换主题时对着它调最直观。
|
|
76
|
+
|
|
77
|
+
## 三层结构
|
|
78
|
+
|
|
79
|
+
| 层 | 模块 | 内容 |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| 令牌 | `tokens` | `COLOR_*`(全部为浅/深二元组)、`FONT_*`、`RADIUS_*`、`SPACE_*` |
|
|
82
|
+
| 主题 | `theme` | `is_dark()`、`color_of()`、`apply_appearance()`、`repaint_native()` |
|
|
83
|
+
| 组件 | `buttons` / `inputs` / `dropdown` / `layout` / `scroll_list` | 见下 |
|
|
84
|
+
|
|
85
|
+
## 组件
|
|
86
|
+
|
|
87
|
+
**按钮**(`buttons`)
|
|
88
|
+
|
|
89
|
+
- `primary_button(master, text, command, *, width=120, height=38, radius=9, font=FONT_BODY)`
|
|
90
|
+
- `soft_button(..., width=76, height=30, font=FONT_SMALL, border=False)` —— 次要操作
|
|
91
|
+
- `danger_button(...)` —— 删除一类不可逆操作
|
|
92
|
+
- `FlatButton(CTkButton)` / `SoftButton(FlatButton)` —— 卡片里的小按钮,宽度按文字实测
|
|
93
|
+
(内部是 `CTkButton` 子类,所以有圆角)
|
|
94
|
+
|
|
95
|
+
**输入**(`inputs`)
|
|
96
|
+
|
|
97
|
+
- `toolbar_entry(master, placeholder, *, height=40)` —— 工具条里的搜索框,聚焦时描边变主色
|
|
98
|
+
- `form_entry(master, *, show="", placeholder="", height=38, password=False)`
|
|
99
|
+
- `segmented(master, values, command=None, *, width=300, height=34, font=FONT_SMALL)`
|
|
100
|
+
- `switch(master, command=None, *, width=44)`
|
|
101
|
+
|
|
102
|
+
**下拉**(`dropdown`)
|
|
103
|
+
|
|
104
|
+
- `DropField(master, *, values_provider, command=None, placeholder="", height=36)` —— 自绘候选卡片,
|
|
105
|
+
不用 `CTkComboBox`,因为系统下拉框在深浅色之间很难统一
|
|
106
|
+
|
|
107
|
+
**布局**(`layout`)
|
|
108
|
+
|
|
109
|
+
- `page_header(master, title) -> (head, info)` —— 左标题右信息
|
|
110
|
+
- `section_title(master, text)`、`card(master)`、`divider(master)`
|
|
111
|
+
- `field_label(master, text, *, width=112)`、`hint_label(master, text)`
|
|
112
|
+
- `empty_hint(master, title, detail="")` —— 空态
|
|
113
|
+
- `scrollable(master)` / `style_scrollable(frame)` —— 统一滚动条的宽度与配色
|
|
114
|
+
|
|
115
|
+
**列表**(`scroll_list`)
|
|
116
|
+
|
|
117
|
+
- `LazyList(master, render_card, *, key_of=None, first_batch=12, load_more=8, ...)`
|
|
118
|
+
|
|
119
|
+
只创建可见的一批卡片,滚到底再补下一批;内容不足以填满视口时自动补齐。
|
|
120
|
+
卡片工厂由调用方提供,所以同一个列表能装任何东西:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
def make_card(parent, item):
|
|
124
|
+
card = ctk.CTkFrame(parent, corner_radius=12, border_width=1, border_color=COLOR_BORDER)
|
|
125
|
+
ctk.CTkLabel(card, text=item["title"], anchor="w").pack(fill="x", padx=16, pady=(14, 0))
|
|
126
|
+
return card
|
|
127
|
+
|
|
128
|
+
listing = LazyList(frame, make_card, key_of=lambda item: item["id"])
|
|
129
|
+
listing.pack(fill="both", expand=True)
|
|
130
|
+
listing.render(items)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 设计令牌
|
|
134
|
+
|
|
135
|
+
颜色全部是 `(浅色, 深色)` 二元组,交给 `color_of()` 按当前外观取值:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from ctk_kit import color_of
|
|
139
|
+
from ctk_kit.tokens import COLOR_ACCENT
|
|
140
|
+
|
|
141
|
+
color_of(COLOR_ACCENT) # 深色下返回 "#2f6fed"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`LazyList`、`segmented` 这类控件需要跟随外观重建的,切主题后调用 `apply_appearance(mode)`,
|
|
145
|
+
再重建相关控件即可(`repaint_native()` 用于原生 tk 控件,它们的 `configure` 被 CTk 接管过)。
|
|
146
|
+
|
|
147
|
+
## 目录
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
ctk_kit/
|
|
151
|
+
├─ tokens.py 设计令牌
|
|
152
|
+
├─ theme.py 取色 / 外观切换 / 原生控件重绘
|
|
153
|
+
├─ buttons.py 按钮
|
|
154
|
+
├─ inputs.py 输入框 / 分段选择 / 开关
|
|
155
|
+
├─ dropdown.py 自绘下拉
|
|
156
|
+
├─ layout.py 页头、卡片、分隔线、空态、滚动容器
|
|
157
|
+
└─ scroll_list.py 懒加载列表
|
|
158
|
+
|
|
159
|
+
examples/
|
|
160
|
+
└─ showcase.py 全组件展示(八个页面,也可当模板改)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## 测试
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
pip install -e ".[test]"
|
|
167
|
+
pytest
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
测试跑在真实 Tk 窗口里(窗口全透明,不会在屏幕上闪),覆盖令牌、主题、按钮、输入框、
|
|
171
|
+
下拉、布局、懒加载列表,以及 `examples/showcase.py` 的八个示例页;没有图形环境时相关用例自动 skip。
|
|
172
|
+
|
|
173
|
+
CI 在 GitHub Actions 上跑 Python 3.8 – 3.14 全矩阵(`.github/workflows/ci.yml`),
|
|
174
|
+
无头环境下用 Xvfb 提供虚拟屏幕;`CI` 环境变量存在时如果建不出窗口会直接失败,而不是静默跳过。
|
|
175
|
+
|
|
176
|
+
## 发布
|
|
177
|
+
|
|
178
|
+
版本号只写在 `pyproject.toml` 的 `version` 字段里,发布流程全自动:
|
|
179
|
+
|
|
180
|
+
1. 改 `pyproject.toml` 的 `version`(例如 `0.1.0` → `0.1.1`),同步更新 `CHANGELOG.md`;
|
|
181
|
+
2. 提交并 `git push` 到 Gitee;
|
|
182
|
+
3. 镜像自动同步到 GitHub,Actions 跑完测试与构建后,会比较 PyPI 上的最新版本——
|
|
183
|
+
本地版本更新才发布,同版本重推不会报错。
|
|
184
|
+
|
|
185
|
+
首次发布前需要在 PyPI 的 *Publishing* 页面给 GitHub 仓库
|
|
186
|
+
`DashSalter/ctk-kit` 添加 Trusted Publisher(workflow 文件名 `ci.yml`,环境留空),
|
|
187
|
+
之后由 `pypa/gh-action-pypi-publish` 凭 OIDC 换短期令牌上传,仓库里不需要存密码。
|
|
188
|
+
|
|
189
|
+
## 已知的坑
|
|
190
|
+
|
|
191
|
+
这些都是踩过的,记下来省得再踩:
|
|
192
|
+
|
|
193
|
+
- `CTkLabel` 不支持 `border_width` / `border_color`,想加边框只能裹一层 `CTkFrame`。
|
|
194
|
+
- `CTkSegmentedButton` 同样不接受 `border_*`,传了会抛 `ValueError`。
|
|
195
|
+
- `CTkScrollbar.set()` 内部会调 `update_idletasks()`,而 `update_idletasks` 会立刻执行
|
|
196
|
+
`after_idle` 排的回调——用 `after_idle` 排分批渲染会在这个调用里递归建卡,改用 `after(1, ...)`。
|
|
197
|
+
- 滚动区域变化后,Tk 会回放一次 `yscrollcommand(0, 1)`。判断「滚到底」不能信回调参数,
|
|
198
|
+
要读 `canvas.yview()`。
|
|
199
|
+
- customtkinter 接管了 `tk.Frame.configure`,给原生控件改背景色得走
|
|
200
|
+
`widget.tk.call(widget._w, "configure", "-background", bg)`,否则会碰到已销毁的子控件。
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
MIT
|
ctk_kit-0.1.0/README.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# ctk-kit
|
|
2
|
+
|
|
3
|
+
[](https://github.com/DashSalter/ctk-kit/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/ctk-kit/)
|
|
5
|
+
[](https://pypi.org/project/ctk-kit/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
面向 [CustomTkinter](https://github.com/TomSchimansky/CustomTkinter) 的轻量界面基件:
|
|
9
|
+
一套深浅色设计令牌、一批常用控件,以及一个会自动分页的懒加载列表。
|
|
10
|
+
支持 Python 3.8 – 3.14。
|
|
11
|
+
|
|
12
|
+
写它的起因很朴素——每个 customtkinter 项目都要重新调一遍颜色、圆角、按钮宽度和滚动列表的
|
|
13
|
+
分批渲染,调完还很难看齐。ctk-kit 把这些收成一层薄薄的公共件,项目之间可以直接复用。
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
pip install ctk-kit
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import customtkinter as ctk
|
|
21
|
+
from ctk_kit import apply_appearance, primary_button, page_header
|
|
22
|
+
|
|
23
|
+
apply_appearance("Dark")
|
|
24
|
+
app = ctk.CTk()
|
|
25
|
+
|
|
26
|
+
head, info = page_header(app, "全部记录")
|
|
27
|
+
head.pack(fill="x", padx=20, pady=(16, 8))
|
|
28
|
+
primary_button(app, "新建", lambda: None).pack()
|
|
29
|
+
app.mainloop()
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
看实际效果:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
git clone https://gitee.com/kuangjianke/ctk-kit
|
|
36
|
+
cd ctk-kit
|
|
37
|
+
python examples/showcase.py
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
展示程序有八个页面:总览、基件、按钮、输入、布局、列表、主题、表单,把每个公开构建都用一遍。
|
|
41
|
+
基件页把 24 个色值连同浅/深两套十六进制值一起列出来,换主题时对着它调最直观。
|
|
42
|
+
|
|
43
|
+
## 三层结构
|
|
44
|
+
|
|
45
|
+
| 层 | 模块 | 内容 |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| 令牌 | `tokens` | `COLOR_*`(全部为浅/深二元组)、`FONT_*`、`RADIUS_*`、`SPACE_*` |
|
|
48
|
+
| 主题 | `theme` | `is_dark()`、`color_of()`、`apply_appearance()`、`repaint_native()` |
|
|
49
|
+
| 组件 | `buttons` / `inputs` / `dropdown` / `layout` / `scroll_list` | 见下 |
|
|
50
|
+
|
|
51
|
+
## 组件
|
|
52
|
+
|
|
53
|
+
**按钮**(`buttons`)
|
|
54
|
+
|
|
55
|
+
- `primary_button(master, text, command, *, width=120, height=38, radius=9, font=FONT_BODY)`
|
|
56
|
+
- `soft_button(..., width=76, height=30, font=FONT_SMALL, border=False)` —— 次要操作
|
|
57
|
+
- `danger_button(...)` —— 删除一类不可逆操作
|
|
58
|
+
- `FlatButton(CTkButton)` / `SoftButton(FlatButton)` —— 卡片里的小按钮,宽度按文字实测
|
|
59
|
+
(内部是 `CTkButton` 子类,所以有圆角)
|
|
60
|
+
|
|
61
|
+
**输入**(`inputs`)
|
|
62
|
+
|
|
63
|
+
- `toolbar_entry(master, placeholder, *, height=40)` —— 工具条里的搜索框,聚焦时描边变主色
|
|
64
|
+
- `form_entry(master, *, show="", placeholder="", height=38, password=False)`
|
|
65
|
+
- `segmented(master, values, command=None, *, width=300, height=34, font=FONT_SMALL)`
|
|
66
|
+
- `switch(master, command=None, *, width=44)`
|
|
67
|
+
|
|
68
|
+
**下拉**(`dropdown`)
|
|
69
|
+
|
|
70
|
+
- `DropField(master, *, values_provider, command=None, placeholder="", height=36)` —— 自绘候选卡片,
|
|
71
|
+
不用 `CTkComboBox`,因为系统下拉框在深浅色之间很难统一
|
|
72
|
+
|
|
73
|
+
**布局**(`layout`)
|
|
74
|
+
|
|
75
|
+
- `page_header(master, title) -> (head, info)` —— 左标题右信息
|
|
76
|
+
- `section_title(master, text)`、`card(master)`、`divider(master)`
|
|
77
|
+
- `field_label(master, text, *, width=112)`、`hint_label(master, text)`
|
|
78
|
+
- `empty_hint(master, title, detail="")` —— 空态
|
|
79
|
+
- `scrollable(master)` / `style_scrollable(frame)` —— 统一滚动条的宽度与配色
|
|
80
|
+
|
|
81
|
+
**列表**(`scroll_list`)
|
|
82
|
+
|
|
83
|
+
- `LazyList(master, render_card, *, key_of=None, first_batch=12, load_more=8, ...)`
|
|
84
|
+
|
|
85
|
+
只创建可见的一批卡片,滚到底再补下一批;内容不足以填满视口时自动补齐。
|
|
86
|
+
卡片工厂由调用方提供,所以同一个列表能装任何东西:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
def make_card(parent, item):
|
|
90
|
+
card = ctk.CTkFrame(parent, corner_radius=12, border_width=1, border_color=COLOR_BORDER)
|
|
91
|
+
ctk.CTkLabel(card, text=item["title"], anchor="w").pack(fill="x", padx=16, pady=(14, 0))
|
|
92
|
+
return card
|
|
93
|
+
|
|
94
|
+
listing = LazyList(frame, make_card, key_of=lambda item: item["id"])
|
|
95
|
+
listing.pack(fill="both", expand=True)
|
|
96
|
+
listing.render(items)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 设计令牌
|
|
100
|
+
|
|
101
|
+
颜色全部是 `(浅色, 深色)` 二元组,交给 `color_of()` 按当前外观取值:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from ctk_kit import color_of
|
|
105
|
+
from ctk_kit.tokens import COLOR_ACCENT
|
|
106
|
+
|
|
107
|
+
color_of(COLOR_ACCENT) # 深色下返回 "#2f6fed"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`LazyList`、`segmented` 这类控件需要跟随外观重建的,切主题后调用 `apply_appearance(mode)`,
|
|
111
|
+
再重建相关控件即可(`repaint_native()` 用于原生 tk 控件,它们的 `configure` 被 CTk 接管过)。
|
|
112
|
+
|
|
113
|
+
## 目录
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
ctk_kit/
|
|
117
|
+
├─ tokens.py 设计令牌
|
|
118
|
+
├─ theme.py 取色 / 外观切换 / 原生控件重绘
|
|
119
|
+
├─ buttons.py 按钮
|
|
120
|
+
├─ inputs.py 输入框 / 分段选择 / 开关
|
|
121
|
+
├─ dropdown.py 自绘下拉
|
|
122
|
+
├─ layout.py 页头、卡片、分隔线、空态、滚动容器
|
|
123
|
+
└─ scroll_list.py 懒加载列表
|
|
124
|
+
|
|
125
|
+
examples/
|
|
126
|
+
└─ showcase.py 全组件展示(八个页面,也可当模板改)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## 测试
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pip install -e ".[test]"
|
|
133
|
+
pytest
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
测试跑在真实 Tk 窗口里(窗口全透明,不会在屏幕上闪),覆盖令牌、主题、按钮、输入框、
|
|
137
|
+
下拉、布局、懒加载列表,以及 `examples/showcase.py` 的八个示例页;没有图形环境时相关用例自动 skip。
|
|
138
|
+
|
|
139
|
+
CI 在 GitHub Actions 上跑 Python 3.8 – 3.14 全矩阵(`.github/workflows/ci.yml`),
|
|
140
|
+
无头环境下用 Xvfb 提供虚拟屏幕;`CI` 环境变量存在时如果建不出窗口会直接失败,而不是静默跳过。
|
|
141
|
+
|
|
142
|
+
## 发布
|
|
143
|
+
|
|
144
|
+
版本号只写在 `pyproject.toml` 的 `version` 字段里,发布流程全自动:
|
|
145
|
+
|
|
146
|
+
1. 改 `pyproject.toml` 的 `version`(例如 `0.1.0` → `0.1.1`),同步更新 `CHANGELOG.md`;
|
|
147
|
+
2. 提交并 `git push` 到 Gitee;
|
|
148
|
+
3. 镜像自动同步到 GitHub,Actions 跑完测试与构建后,会比较 PyPI 上的最新版本——
|
|
149
|
+
本地版本更新才发布,同版本重推不会报错。
|
|
150
|
+
|
|
151
|
+
首次发布前需要在 PyPI 的 *Publishing* 页面给 GitHub 仓库
|
|
152
|
+
`DashSalter/ctk-kit` 添加 Trusted Publisher(workflow 文件名 `ci.yml`,环境留空),
|
|
153
|
+
之后由 `pypa/gh-action-pypi-publish` 凭 OIDC 换短期令牌上传,仓库里不需要存密码。
|
|
154
|
+
|
|
155
|
+
## 已知的坑
|
|
156
|
+
|
|
157
|
+
这些都是踩过的,记下来省得再踩:
|
|
158
|
+
|
|
159
|
+
- `CTkLabel` 不支持 `border_width` / `border_color`,想加边框只能裹一层 `CTkFrame`。
|
|
160
|
+
- `CTkSegmentedButton` 同样不接受 `border_*`,传了会抛 `ValueError`。
|
|
161
|
+
- `CTkScrollbar.set()` 内部会调 `update_idletasks()`,而 `update_idletasks` 会立刻执行
|
|
162
|
+
`after_idle` 排的回调——用 `after_idle` 排分批渲染会在这个调用里递归建卡,改用 `after(1, ...)`。
|
|
163
|
+
- 滚动区域变化后,Tk 会回放一次 `yscrollcommand(0, 1)`。判断「滚到底」不能信回调参数,
|
|
164
|
+
要读 `canvas.yview()`。
|
|
165
|
+
- customtkinter 接管了 `tk.Frame.configure`,给原生控件改背景色得走
|
|
166
|
+
`widget.tk.call(widget._w, "configure", "-background", bg)`,否则会碰到已销毁的子控件。
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""ctk-kit —— 面向 CustomTkinter 的轻量界面基件。
|
|
2
|
+
|
|
3
|
+
分三层:
|
|
4
|
+
|
|
5
|
+
- ``tokens`` 设计令牌:颜色(深浅两套)、字体、圆角、间距
|
|
6
|
+
- ``theme`` 取色与外观切换工具,以及原生 tk 控件的重绘
|
|
7
|
+
- 组件 ``buttons`` / ``inputs`` / ``dropdown`` / ``layout`` / ``scroll_list``
|
|
8
|
+
|
|
9
|
+
安装::
|
|
10
|
+
|
|
11
|
+
pip install ctk-kit
|
|
12
|
+
|
|
13
|
+
最小示例::
|
|
14
|
+
|
|
15
|
+
import customtkinter as ctk
|
|
16
|
+
from ctk_kit import primary_button, card, page_header
|
|
17
|
+
|
|
18
|
+
app = ctk.CTk()
|
|
19
|
+
header, info = page_header(app, "备份")
|
|
20
|
+
box = card(app)
|
|
21
|
+
primary_button(box, "立即备份", command=lambda: print("go")).pack(padx=16, pady=16)
|
|
22
|
+
app.mainloop()
|
|
23
|
+
|
|
24
|
+
全组件展示(示例脚本,见仓库 examples/)::
|
|
25
|
+
|
|
26
|
+
python examples/showcase.py
|
|
27
|
+
|
|
28
|
+
仓库: https://gitee.com/kuangjianke/ctk-kit
|
|
29
|
+
镜像: https://github.com/DashSalter/ctk-kit
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
__version__ = "0.1.0"
|
|
35
|
+
|
|
36
|
+
from . import tokens, theme
|
|
37
|
+
from .buttons import (
|
|
38
|
+
FlatButton,
|
|
39
|
+
SoftButton,
|
|
40
|
+
danger_button,
|
|
41
|
+
primary_button,
|
|
42
|
+
soft_button,
|
|
43
|
+
)
|
|
44
|
+
from .dropdown import DropField
|
|
45
|
+
from .inputs import form_entry, segmented, switch, toolbar_entry
|
|
46
|
+
from .layout import (
|
|
47
|
+
card,
|
|
48
|
+
divider,
|
|
49
|
+
empty_hint,
|
|
50
|
+
field_label,
|
|
51
|
+
hint_label,
|
|
52
|
+
page_header,
|
|
53
|
+
scrollable,
|
|
54
|
+
section_title,
|
|
55
|
+
style_scrollable,
|
|
56
|
+
)
|
|
57
|
+
from .scroll_list import LazyList
|
|
58
|
+
from .theme import apply_appearance, color_of, is_dark, repaint_native
|
|
59
|
+
|
|
60
|
+
__all__ = [
|
|
61
|
+
"DropField",
|
|
62
|
+
"FlatButton",
|
|
63
|
+
"LazyList",
|
|
64
|
+
"SoftButton",
|
|
65
|
+
"__version__",
|
|
66
|
+
"apply_appearance",
|
|
67
|
+
"card",
|
|
68
|
+
"color_of",
|
|
69
|
+
"danger_button",
|
|
70
|
+
"divider",
|
|
71
|
+
"empty_hint",
|
|
72
|
+
"field_label",
|
|
73
|
+
"form_entry",
|
|
74
|
+
"hint_label",
|
|
75
|
+
"is_dark",
|
|
76
|
+
"page_header",
|
|
77
|
+
"primary_button",
|
|
78
|
+
"repaint_native",
|
|
79
|
+
"scrollable",
|
|
80
|
+
"section_title",
|
|
81
|
+
"segmented",
|
|
82
|
+
"soft_button",
|
|
83
|
+
"style_scrollable",
|
|
84
|
+
"switch",
|
|
85
|
+
"theme",
|
|
86
|
+
"tokens",
|
|
87
|
+
"toolbar_entry",
|
|
88
|
+
]
|