A reactive, declarative TUI library for Python — indentation is your layout, state changes re-render for you. Powered by Textual.
Project description
tuikinter
响应式、声明式的现代终端 UI 库。 底层是 Textual,上层是一套极简的 API:用 with 块的缩进表达布局,用 state 让界面随数据自动刷新。
A reactive, declarative TUI library for Python. Indentation is your layout; state changes re-render the UI for you.
import tuikinter as ui
count = ui.state(0)
with ui.App("我的应用") as app:
with app.col(pady=1):
ui.label(lambda: f" 计数: {count}") # 读了 count,count 一变它自动刷新
with app.row():
ui.button("-1", on=lambda: count.set(count - 1), variant="error")
ui.button("+1", on=lambda: count.set(count + 1), variant="success")
ui.button("退出", on=app.quit)
app.run()
没有一句 .config(text=...),没有手动刷新。count 变了,那个 label 自己就变了。
安装
pip install tuikinter
需要 Python 3.9+。依赖 textual>=0.40。
为什么是它
tuikinter 不是又一个 tkinter 克隆。它拿了两个现代 UI 框架的好思想,放进终端:
- 缩进即布局。
with app.col():/with app.row():的嵌套就是界面的层级。代码长什么样,界面就长什么样——像 Flutter / SwiftUI 那样。 - 状态驱动。
ui.state(x)是一个响应式値。渲染函数读了哪些 state,就自动订阅哪些;state 一变,只重渲染用到它的那几个控件——像 Vue / MobX 的自动依赖追踪。
核心概念
state —— 响应式状态
count = ui.state(0)
count.get() # 读
count.set(5) # 写
count.value = 5 # 同上
count.update(lambda v: v+1) # 基于旧値算新値
# state 能直接参与运算和格式化,省掉 .get()
count - 1 # = count.get() - 1
f"计数: {count}" # 自动取値
把一个函数传给 ui.label(...) 或 ui.progress(...),它就成了响应式的——函数里读到的 state 一变,控件自动重渲染:
ui.label(lambda: f"你好, {name}!") # name 变 -> 文本变
ui.progress(lambda: count.get() * 10) # count 变 -> 进度变
with 块 —— 布局
with ui.App("标题") as app:
with app.col(): # 竖排 (column)
ui.label("上")
ui.label("下")
with app.row(): # 横排 (row)
ui.label("左")
ui.label("右")
app.run()
col / row 接受 padx / pady 调间距。控件创建时自动认领当前 with 块作为父容器,不需要手动传 parent。
控件
| 工厂函数 | 说明 |
|---|---|
ui.label(text) |
文本。text 可是字符串,也可是返回字符串的函数(响应式) |
ui.button(text, on=fn) |
按钮。on= 是点击回调;variant= 可选 default/primary/success/error/warning |
ui.entry(state=s) |
单行输入。state= 双向绑定;placeholder= / password=True |
ui.checkbox(text, state=s) |
勾选框。state= 双向绑定到布尔 state;on= 变化回调 |
ui.progress(value) |
进度条。value 可是数字或函数(响应式);total= 默认 100 |
一个完整例子
import tuikinter as ui
count = ui.state(0)
name = ui.state("Joshua")
with ui.App("演示") as app:
with app.col(pady=1):
ui.label(lambda: f" 计数: {count}")
with app.row():
ui.button("-1", on=lambda: count.set(count - 1), variant="error")
ui.button("+1", on=lambda: count.set(count + 1), variant="success")
with app.row(pady=1):
ui.label("名字:")
ui.entry(state=name, placeholder="输入...")
ui.label(lambda: f" 你好, {name}!")
ui.progress(lambda: max(0, min(100, count.get() * 10)))
ui.button("退出", on=app.quit)
app.run()
运行 python examples/demo.py 看实际效果。
许可
MIT License。详见 LICENSE。
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tuikinter-0.2.0.tar.gz.
File metadata
- Download URL: tuikinter-0.2.0.tar.gz
- Upload date:
- Size: 12.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2c83d7668bae1ad255db902adec4c2bb40a90ff678c0ed45dccf9ff55164e6b1
|
|
| MD5 |
067637726030eecd85729b46bb8f84c0
|
|
| BLAKE2b-256 |
4c2b1a819341d497869d4aaa8bd6867f5b8f56aa8e6695c1d02b8e0f5eeda792
|
File details
Details for the file tuikinter-0.2.0-py3-none-any.whl.
File metadata
- Download URL: tuikinter-0.2.0-py3-none-any.whl
- Upload date:
- Size: 9.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e2354b4f1a360812be5715c8bb71427fd616f8f739e55fe13fd56359babe2a69
|
|
| MD5 |
652b72178211d4b350d5e5795aae23e8
|
|
| BLAKE2b-256 |
9661f29b4d0c5710942e8b8ffde3ee2940db385fc9d5f68ea02d1158f6019558
|