Skip to content

About

The free-forever and simple Python GUI framework

Resources

Stars

3 stars

Watchers

1 watching

Forks

Latest commit

 

History

106 Commits

Folders and files

Repository files navigation

TkSimpleGUI

TkSimpleGUI

TkSimpleGUI 是一个纯 Tkinter/ttk 的 Python GUI 框架:Python 3.8+ 零第三方依赖 (3.7 需 typing_extensions 一个条件依赖)。声明式布局、面向对象控件、 全局事件总线、统一事件循环——用 Tk 也要有 Qt 的开发体验。

由 PySimpleGUI 4.x(GPLv3)分叉而来,现已是独立的框架:不再兼容上游 API, 全面转向「零事件循环 + 事件装饰器」的现代写法。改名是为了避免与 PySimpleSoft 的商标冲突,同时如实反映项目的独立性。


特性

  • 零事件循环 — 永远不写 while True:window.run() 一个入口, 全局唯一事件循环天然支持多窗口协同
  • 双向绑定 — ts.Var 可观察值容器 + window.bind_var(key, var): 写 var 扇出全部绑定元素,用户改动泵心跳回拉,跨窗口共享同一个 var
  • 事件绑定走装饰器 — @ts.bind_event 绑定模块级 on_* 函数, window / event / values 按参数名自动注入
  • 面向对象控件 — 每个控件都是真正的类实例,属性读写、方法直调, 不再和 window["-KEY-"].update(...) 的字符串寻址缠斗
  • T 前缀命名 — 每个控件类一律以 T 开头(ts.TText / ts.TInput / ts.TButton),一眼即知是本框架控件,全库一个概念只有一个名字
  • 消灭魔术字符串 — Tk 的字符串选项全部类型化为枚举 (ts.Anchor.CENTER、ts.Justify.RIGHT、ts.EventType.DOUBLE_CLICK、 ts.Color.NAVY、ts.Relief.SUNKEN…),枚举值本身就是 Tk 字符串,裸字符串依旧可用
  • dataclass 配置对象 — ts.WindowConfig / ts.ElementOptions 声明式参数包,可共享复用
  • 100% 类型标注 — py.typed(PEP 561),ty 零诊断,IDE 全程补全与检查
  • 超越 Tk — 圆角按钮、图像按钮、文字进度条、全局热键、任务栏进度、 系统托盘、文件拖放、日历控件、表格编辑/排序、拆分器、流式面板……Tk/ttk 没有的这里也有
  • 自绘展示控件 — Element Plus 风格的标签/徽章/头像/统计数值/空状态/结果页/ 步骤条/时间线/骨架屏/警告条/水印/描述列表/卡片/分段控制器/评分/分页器/穿梭框: 全部 TCanvas 自绘或原生组合,随主题自动换色,零新依赖
  • 日志直接进日志框 — TOutput 就是日志框:out.log("...") 一行落笔, 级别配色(debug/info/success/warning/error)+ 时间戳 + 行数上限(环形缓冲)+ 可选文件镜像;ts.log(...) 一行式无对象写入,Logger.attach_logging() 把标准 logging 桥接进来,工作线程写入也不会崩 Tk
  • 封装彻底 — __slots__ 全覆盖、私有属性 + @property、 主题与设置走单例而非模块全局
  • 系统原生外观 — 不调 ts.theme() 就不覆盖任何颜色,ttk 用操作系统原生主题
  • 主题切换动画 — ts.theme("Slate", transition_ms=250) 旧配色缓动混入 新配色,所有打开的窗口逐帧重绘
  • DPI 缩放(Windows) — 一行开启 DPI 感知让高分屏字体真实像素渲染 不再模糊;ts.settings.scaling 一键整体缩放
  • 亮暗跟随 + DWM 美化(Windows) — theme_follow_system 跟随系统 亮暗自动换主题;dark_titlebar 深色标题栏随主题自动切换
  • Python 3.7+ — 3.8+ 零第三方依赖(3.7 需 typing_extensions),Tkinter/ttk + 标准库

与同类库对比

同为 Tkinter 封装的主流方案,与 TkSimpleGUI 的横向对比 (数据来自各家官方文档 / PyPI,2026-10):

TkSimpleGUI FreeSimpleGUI CustomTkinter ttkbootstrap 2.x
定位 OO 重写的现代 Tk 框架 PSG4 社区分叉(原版续命) 现代外观控件集 ttk 主题 + Bootstrap 观感
许可 GPL-3.0-or-later LGPL-3.0 MIT MIT
Python 下限 3.7 3.8+ 3.8+ 3.10+
第三方依赖 无(3.7 需 typing_extensions) 无 darkdetect(可选) Pillow 硬依赖
编程范式 面向对象 + 全局事件总线 过程式 + read 轮询(PSG 契约) 命令回调(无事件抽象) ttk 主题 + 命令回调
API 风格 T 前缀 + snake_case 唯一写法,100% 类型标注 PascalCase 主 + snake 别名(保 PSG 兼容) CTk 前缀 ttkbootstrap 前缀
多窗口 一等公民:隐藏主 root + 全局总线,任意窗口间发事件 read_all_windows 轮询 单窗口为主,多窗口手工管理 单 root 强制,第二个 root 直接报错
布局 [[...]] list-of-lists + pack/grid 抽象 [[...]] list-of-lists 无布局抽象(place 手工) pack/grid 手工
控件数量 60+(含 17 个 Element Plus 风格自绘) PSG4 全家桶(巨石拆包) ~20 个(社区补件碎片化) ttk 全量 + Meter 等增强
主题 5 套手工低饱和配色 + 原生观感(不调 theme 即系统默认) PSG 主题表继承 亮/暗双模式 + json 主题 Bootstrap 色系 + 主题编辑器
类型标注 py.typed,全量 部分 部分 部分
适合谁 要 OO/类型/多窗口/长维护的现代 Python 项目 PSG4 老用户零成本迁移 只需要几个现代观感控件 喜欢 Bootstrap 观感、固定 3.10+

一句话:FreeSimpleGUI 保 PSG 兼容、CustomTkinter 补观感、ttkbootstrap 给主题—— TkSimpleGUI 把这些换成一个统一的现代 OO 框架:事件总线、类型标注、多窗口、 零依赖、3.7 起步。

安装

pip install TkSimpleGUI

快速上手

import TkSimpleGUI as ts

window = ts.Window("Demo", [
    [ts.TText("Hello, TkSimpleGUI!", key="-OUT-")],
    [ts.TInput(key="-IN-"), ts.TButton("Greet")],
    [ts.TButton("Exit")],
])

@ts.bind_event
def on_greet(window, values):
    window["-OUT-"].update(f"Hello, {values['-IN-'] or 'stranger'}!")

@ts.bind_event
def on_exit(window):
    window.close()

window.run()   # 就这一行——没有 while True

多窗口同样零仪式:

main = ts.Window("Main", [[ts.TButton("Open child")], [ts.TButton("Quit")]])
child = ts.Window("Child", [[ts.TText("I am the child")], [ts.TButton("Close me")]],
                  parent=main)

@ts.bind_event
def on_open_child(window):
    child.un_hide()

@ts.bind_event
def on_close_me(window):
    window.close()

main.run()     # 唯一的循环,泵所有窗口

窗口层级

main = ts.Window("Main", layout)
child = ts.Window("Child", layout, parent=main)

child.parent is main        # True
main.children               # [child]
child.is_child_of(main)     # True
child.close()               # 级联关闭自己的子窗口

双向绑定(ts.Var)

ts.Var 是可观察值容器,window.bind_var(key, var) 把元素键桥接到它—— 写 var 扇出到全部绑定元素,用户改动在每个事件泵心跳回拉进 var,并复制到 同 var 的其他绑定元素(两个窗口共享同一个 var 也一样):

count = ts.Var(0)

window = ts.Window("计数器", [
    [ts.TButton("+1", key="-ADD-")],
    [ts.TInput("", key="-N-")],
    [ts.TText("", key="-ECHO-")],
], finalize=True)

window.bind_var("-N-", count)     # 输入框 ↔ var
window.bind_var("-ECHO-", count)  # 显示框 ← var(扇出目标)

count.value = 1                   # 输入框与显示框同时变 "1"
# 在输入框里打字 → 下一次泵 tick:count.value 更新,显示框跟着变

@ts.bind_event("-ADD-")
def on_add(window, values):
    count.value = int(count.value or 0) + 1

window.run()

绑定时 var 的值胜出(同 tk Variable 的直觉;Var() 默认 None 则不动元素, 首个泵 tick 采纳元素现值)。要求 finalize 后的窗口;绑定的元素其 update() 须接受 value=(与 window.fill() 同一契约)。解绑用 window.unbind_var(key), 窗口关闭时自动解绑。

文件拖放(Windows)

window.drop_target(func) 让窗口接受资源管理器拖来的文件——纯 ctypes 走 WM_DROPFILES shell 路线,零依赖、无需 tkdnd 扩展:

window = ts.Window("拖放", [
    [ts.TText("把文件拖进来", key="-HINT-")],
    [ts.TMultiline("", key="-LOG-")],
], finalize=True)

def on_drop(files):
    window["-LOG-"].write("\n".join(files) + "\n")

window.drop_target(on_drop)   # None 撤销;重复注册即替换
window.run()

files 是绝对路径字符串列表。回调在主线程随消息泵触发,可直接操作 控件;关窗自动撤销。非 Windows 平台抛 NotImplementedError。

主题切换动画

ts.theme() 的第二个参数让整窗配色平滑过渡:旧主题的调色板缓动混入新 主题,期间所有打开的窗口逐帧重绘(ttk 样式表、经典控件与自绘控件一起变):

ts.theme("Slate", transition_ms=250)   # 默认 0 = 立即切换

要求切换前后都是非原生主题(None / System 出现在任意一端就直接跳变), 且至少有一个活窗口。混合发生在主题管理器的取色层,单色覆盖 (theme_background_color(...) 等)照常生效。

DPI 缩放(Windows)

一行声明 DPI 感知后,Tk 拿到真实屏幕 DPI:点数单位的字体按真实像素 渲染——高分屏上不再模糊放大(默认关闭;Tk 8.6 不支持 per-monitor, 框架按系统级声明——Tk 实际支持的级别):

ts.settings.dpi_aware = True    # 必须在第一个窗口创建前设置

不开启时维持 Windows 对非感知进程的 DPI 虚拟化,行为与历史版本完全一致 (ts.set_dpi_awareness() 手动 API 保留,重复调用无害)。

ts.settings.scaling 是全局缩放倍率(默认 None = 不缩放):设成 1.25 / 1.5 后,字体与布局像素(元素间距、窗口边距/尺寸、画布控件 尺寸、ttk 内边距)一起等比放大——想在 4K 屏上得到 CTk 式整体放大的话 (配合 dpi_aware = True 效果最佳):

ts.settings.scaling = 1.5       # 建窗口前设置;建窗后改不影响已画元素

缩放范围说明:字符数定宽控件(输入框/按钮/标签)随字体自动跟随;自绘 画布元素的整体尺寸(图表画布、标签/徽章/头像等)按倍率缩放,但内部 装饰字面量(图表坐标轴边距、图形内衬)保持 96-DPI 逻辑像素;窗口位置 坐标与 PhotoImage 像素数据不缩放;跨显示器拖动不触发动态重排 (Tk 8.6 限制)。

亮暗跟随与 DWM 美化(Windows)

跟随系统亮暗:开启后每 2 秒轮询一次 Windows 个性化设置(注册表 AppsUseLightTheme,CTk 的跟随思路),系统亮暗翻转时自动切换主题—— 亮态用 theme_light(默认 Daylight)、暗态用 theme_dark(默认 Slate),映射可改成任何主题名:

ts.settings.theme_follow_system = True   # 建窗口前设置
ts.settings.theme_light = "Sage"         # 可选:自定义亮暗映射
ts.settings.theme_dark = "Dusk"

深色标题栏:Window(dark_titlebar=...) 三种取值——None(默认) 自动:标题栏随当前主题的亮暗性格走(暗主题配暗标题栏),主题切换 即跟随;原生外观下跟随 Windows 系统亮暗设置。True/False 强制指定。 运行时 window.set_dark_titlebar(None) 恢复自动。Windows 10 1809+, 更老版本静默忽略:

window = ts.Window("Dark app", layout, dark_titlebar=True)

Mica / Acrylic 背景(Win11 22H2+):window.set_backdrop("mica")—— DWM 边框延伸进客户区再挂系统背景材质。诚实说明:Tk 自己画的背景是 不透明的,材质只在客户区裸露处可见(比如配合透明色键);"none" 恢复 默认。窗口圆角交由系统默认,不提供改角接口。非 Windows 平台这些调用 是安全的 no-op(_dwm/_appearance 模块任意平台可导入)。

声明式配置(dataclass)

import TkSimpleGUI as ts

label_style = ts.ElementOptions(justification=ts.Justify.CENTER,
                                expand_x=True, pad=(8, 4))

layout = [
    [ts.TText("Title", config=label_style)],
    [ts.TText("Body", config=label_style)],
]

cfg = ts.WindowConfig(title="Settings", size=(420, 280), resizable=True,
                      layout=layout)
window = ts.Window(config=cfg, finalize=True)   # 布局进 config,或直接 layout=

日志写进日志框(TOutput 控件)

TOutput 就是日志框,日志层直接长在它上面——没有第二个输出通道:

log_box = ts.TOutput(size=(90, 12), key="-LOG-")

log_box.log("采样已启动")                     # INFO,主题字色
log_box.log("通道 3 噪声偏大", level="warning")  # 琥珀色
log_box.log("通道 7 断线", level="error")      # 与错误提示条同一个红

# 一行式:key 可省(默认取最新窗口里的第一个 TOutput)
ts.log("任意位置写一行", key="-LOG-")

# 需要更正式的日志:行数上限(环形缓冲)、文件镜像、标准 logging 桥接
logger = log_box.logger(max_lines=500, mirror="run.log")
logger.attach_logging("INFO")                 # logging.* 也进这个框
logging.getLogger("采集服务").warning("队列积压")  # → 12:03:44 WARNING 采集服务: 队列积压

# 工作线程里也能安全写(Logger 排队,回到 Tk 线程落笔)
def sample_channels():
    logger.info("开始采样")
    return "12 个通道"

window.start_task(sample_channels, end_key="-DONE-")

@ts.bind_event("-DONE-")
def on_done(window, values):
    result = values["-DONE-"]             # 成功=返回值;失败=异常对象
    if isinstance(result, BaseException):
        logger.error(f"采集失败:{result}")  # traceback 也会进 TkSimpleGUI.task
    else:
        logger.success(f"采集完成:{result}")

级别:debug(灰)/ info(主题字色)/ success(绿)/ warning(琥珀)/ error、critical(红);每行自带时间戳(timestamp="%H:%M:%S",可改可关), color= 可按业务覆盖。找关键字用 search_all(),右键菜单可复制/清空。

目录结构

TkSimpleGUI/
├── src/TkSimpleGUI/            # 对象导向包(import TkSimpleGUI)
│   ├── __init__.py             # 公开 API(控件类一律 T 前缀)
│   ├── enums.py                # 13 类 Tk 字符串枚举(Anchor/Color/EventType…)
│   ├── config.py               # WindowConfig / ElementOptions dataclass
│   ├── _version.py             # 版本信息
│   ├── constants.py            # 不可变常量
│   ├── _theme_data.py          # 5 套手工主题表(含 System 原生)
│   ├── _theming.py             # ThemeManager(主题状态封装)
│   ├── _typing_compat.py       # 3.7 的 Literal 兼容层
│   ├── settings.py             # Settings 单例(全局选项封装)
│   ├── utils.py                # rgb、Timer、平台检测、DPI 感知
│   ├── event.py                # TkSimpleEvent 全局事件总线 + default_app
│   ├── actions.py              # Action / ActionList(Delphi TActionList 对标)
│   ├── user_settings.py        # UserSettings(JSON 持久化)
│   ├── animation.py            # fade/slide/progress 动画辅助
│   ├── hotkey.py               # 全局热键 + 任务栏进度(Win32/COM)
│   ├── input_blocker.py        # 系统级输入屏蔽(模态加强)
│   ├── popup.py                # 基于 Window 本体的弹窗族
│   ├── elements/
│   │   ├── base.py             # Element(ABC) + 右键菜单 + 网格布局引擎
│   │   ├── _paint.py           # 自绘控件的共享绘制/调色基础层
│   │   ├── widgets.py          # TText/TInput/TCombo/TListbox/TSpin/TCheckbox/TRadio…
│   │   ├── buttons.py          # TButton 及浏览/开关/图像变体
│   │   ├── fancy.py            # 圆角按钮/图像按钮/文字进度条/仪表盘/TLED
│   │   ├── media.py            # TImage/TCanvas/TGraph(图元句柄)
│   │   ├── containers.py       # TFrame/TColumn/TSplitter/TTabGroup/TToolbar…
│   │   ├── calendar.py         # 内嵌月历
│   │   ├── chart.py            # 图表(9 种类型 + 误差棒/参考线/直方图)
│   │   ├── display.py          # 标签/徽章/头像/统计/空状态/结果页/骨架屏/警告条/水印
│   │   ├── panels.py           # 卡片/描述列表/步骤条/时间线
│   │   ├── selection.py        # 分段控制器/评分/分页器/穿梭框
│   │   └── data.py             # TTable(排序/编辑/图标)、TTree
│   └── window/
│       ├── window.py           # Window:统一循环、层级、定时器、剪贴板
│       └── system_tray.py      # SystemTray(托盘图标/菜单/气泡/事件)
├── demos/                      # 演示脚本(feature showcase + 基本模板)
├── tests/test_package.py       # 测试套件(298 项,pytest/unittest 均可跑)
├── todo.md                     # 路线图
├── pyproject.toml
└── README.md

开发与测试

pip install -e .
python -m pytest tests -q             # 299 项测试(每测试 30s 超时守护)
python -m unittest discover tests     # 同一套测试的 unittest 跑法
python tests/check_types.py           # ty 类型检查守卫
python tests/check_syntax.py          # 3.7 语法门(用运行中解释器的 ast 解析全部 .py)
python demos/showcase.py --smoke      # showcase 冒烟自检

版本信息

  • Version: 0.1.0
  • Python: >= 3.7
  • License: GPL-3.0-or-later(继承自上游 PySimpleGUI 4.x)

About

The free-forever and simple Python GUI framework

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages