
使用 Slint Python 绑定运行 Printer Demo从环境搭建到数据绑定与国际化实战【免费下载链接】slintSlint is an open-source declarative GUI toolkit to build native user interfaces for Rust, C, JavaScript, or Python apps.项目地址: https://gitcode.com/GitHub_Trending/sl/slint本文以 Slint 仓库中 demos/printerdemo/python/README.md 为主线完整讲解如何基于 uv 工具链运行 Python 版 Printer Demo打印设备仿真界面并深入到 main.py 源码剖析其如何通过ListModel模型、Timer定时器、slint.callback装饰器与 gettext 国际化机制将 .slint 声明式 UI 与 Python 业务逻辑无缝衔接。读完本文你将掌握 Slint Python 绑定的标准运行流程、加载.slint组件的方式以及UI 层声明、Python 层驱动的混合开发范式可直接迁移到自己的 Python GUI 项目中。一、Printer Demo 是什么Printer Demo 是 Slint 官方演示项目之一模拟了一台多功能打印机的完整操作界面包含主页、复印、扫描、打印、墨水状态、USB 与设置等多个页面。它通过同一套.slint声明式 UI 代码位于 demos/printerdemo/ui分别提供了 Rust、C、Node.js、Python 和 Zephyr 嵌入式 等多个语言版本是学习同一 UI、多语言绑定的绝佳样例。其中 Python 版的核心入口是 main.py它本身不包含任何 UI 布局代码全部界面均来自ui目录下的.slint文件main.py 只负责三件事通过slint.loader加载并实例化.slint中声明的MainWindow用 Python 对象ListModel、回调函数填充并驱动 UI 声明的数据与事件启动事件循环运行窗口。二、环境准备Python 3、pip 与 uv根据 README 的 Prerequisites 部分运行前需要安装三个工具工具作用Python 3 中的requires-python 3.12pipPython 包管理工具用于安装依赖uv高性能的 Python 包管理与虚拟环境工具负责一键解析依赖并运行项目其中uv是本 Demo 推荐的启动方式。从 pyproject.toml 可以看到依赖关系被声明为[project] name python version 1.10.0 description Slint Printer Demo for Python requires-python 3.12 dependencies [slint] [tool.uv.sources] slint { path ../../../api/python/slint, editable true }关键点在于[tool.uv.sources]一节它把slint包直接指向仓库内的 api/python/slint 目录并以editable可编辑模式安装。这意味着本地修改 Python 绑定源码后无需重新安装即可生效非常适合配合该 Demo 调试和学习绑定层的实现细节。若你希望使用发布到 PyPI 的正式版slint只需删除这一节让 uv 从 PyPI 拉取即可。三、一键运行uv run main.pyREADME 给出的运行命令非常简洁uv run main.pyuv run会依次完成根据 pyproject.toml 创建或复用虚拟环境解析并安装slint依赖此处为仓库本地可编辑路径在虚拟环境中执行python main.py。提示如果不想使用 uv也可以先pip install slint再直接python demos/printerdemo/python/main.py前提是已安装满足3.12的 Python 版本。启动后程序入口执行了main.py最后两行main_window MainWindow() main_window.run()其中MainWindow的基类来自slint.loader.ui.printerdemo.MainWindowrun()是 Slint Python 绑定为组件实例提供的事件循环入口其类型签名可参见 api/python/slint/slint/slint.pyi 中的ComponentInstance.run相关 API。四、UI 骨架.slint 中声明的 MainWindow虽然 README 只指向了 main.py但理解 Demo 必须配合 UI 源码。.slint文件中的根组件定义在 demos/printerdemo/ui/printerdemo.slintexport component MainWindow inherits Window { callback quit(); min-width: 772px; min-height: 504px; title: tr(Slint printer demo); Rectangle { HorizontalLayout { side-bar : Sidebar { } main-view : Rectangle { if PrinterState.active-page Page.home: home-page : HomePage { } if PrinterState.active-page Page.settings: settings-page : SettingsPage { } if PrinterState.active-page Page.ink: ink-page : InkPage { } } } } }这里可以看到几个与 Python 层交互密切的要素callback quit();—— 在.slint中声明了一个回调Python 侧通过slint.callback装饰同名方法实现if PrinterState.active-page ...—— 通过全局对象PrinterState的active-page属性驱动页面切换tr(...)—— 字符串包裹在翻译宏中配合后面介绍的 gettext 机制支持多语言。各个页面组件HomePage、SettingsPage、InkPage、CopyPage、ScanPage、PrintPage、UsbPage都定义在 demos/printerdemo/ui/pages 目录中并通过 pages.slint 统一导出。五、Python 与 UI 的桥梁slint.loader 与全局对象main.py 开头通过slint.loader以动态加载方式引用 UIimport slint sys.path.append(os.path.join(os.path.dirname(__file__), ..)) PrinterQueueItem slint.loader.ui.printerdemo.PrinterQueueItem class MainWindow(slint.loader.ui.printerdemo.MainWindow): def __init__(self): super().__init__()slint.loader会从 Python 包的相对路径中找到对应模块下的.slint文件并即时编译因此 Demo 目录结构python/与ui/平级至关重要sys.path.append(..., ..)正是为了把ui所在目录加入模块搜索路径使ui.printerdemo能解析到ui/printerdemo.slint。PrinterQueueItem则直接对应.slint中声明的结构体类型定义于 demos/printerdemo/ui/pages/printer_queue.slintexport struct PrinterQueueItem { status: string, progress: int, title: string, owner: string, pages: int, size: string, submission-date: string }Python 侧即可用它构造符合 UI 期望的数据对象如PrinterQueueItem(statuswaiting, progress0, titletitle, ...)。六、数据驱动ListModel 与打印机队列打印队列是 Demo 的核心交互数据。在 printer_queue.slint 中队列数据被声明为一个全局对象export global PrinterQueue { in property [PrinterQueueItem] printer-queue: [ /* 4 条预置 mock 数据 */ ]; callback start-job(string); callback cancel-job(int); callback pause-job(int); }而 UI 通过for queue-item[idx] in PrinterQueue.printer-queue渲染列表宽屏用WidePrinterQueueList窄屏用NarrowPrinterQueueList。问题在于.slint声明的属性数组默认是只读的无法在运行时增删。main.py 的处理方式是经典的UI 数据接管模式# Copy the read-only mock data from the UI into a mutable ListModel self.printer_queue ListModel(self.PrinterQueue.printer_queue) self.PrinterQueue.printer_queue self.printer_queue即先把 UI 中的只读 mock 数据拷贝进 Python 的ListModel再把它写回全局对象属性。此后 Python 对self.printer_queue的增删改会实时驱动 UI 列表刷新——这正是 Slint 中ListModel的核心价值可变的、带变更通知的数组模型。墨水状态也采用同样手法初始化self.PrinterState.ink_levels ListModel([{...}, ...])颜色值直接用Color(#0ff)等十六进制构造。七、模拟打印进度Timer 定时器真实的打印进度当然不存在于一个 Demo 中main.py 用Timer模拟from slint import Color, ListModel, Timer, TimerMode self.print_progress_timer Timer() self.print_progress_timer.start( TimerMode.Repeated, timedelta(seconds1), self.update_jobs )Timer.start(mode, interval, callback)的签名见 api/python/slint/slint/slint.pyi 中Timer类以TimerMode.Repeated模式每 1 秒触发一次update_jobs。update_jobs实现了简单的队列仿真逻辑def update_jobs(self): if len(self.printer_queue) 0: return top_item copy.copy(self.printer_queue[0]) top_item.progress 1 if top_item.progress 100: del self.printer_queue[0] # 打印完成出队 if len(self.printer_queue) 0: return top_item copy.copy(self.printer_queue[0]) self.printer_queue[0] top_item # 写回模型触发 UI 刷新细节值得注意取出队首项后用copy.copy创建副本、修改progress后再写回下标0。这是因为ListModel的元素替换__setitem__才会触发行已变更通知若直接原地修改对象字段UI 无法感知变化。这是使用 Slint 模型时容易踩坑、但 Demo 已示范正确写法的地方。对应地UI 中的进度条组件ProgressBar同文件内定义通过width: max(6px, root.progress * parent.width / 100)将 0–100 的整型进度映射为可视宽度。八、事件回流slint.callback 与全局回调.slint中声明的callback在 Python 侧通过slint.callback装饰器绑定实现。main.py 中有三个典型例子slint.callback def quit(self): self.hide() slint.callback(global_namePrinterQueue, namestart_job) def push_job(self, title): self.printer_queue.append(PrinterQueueItem( statuswaiting, progress0, titletitle, ownerMe, pages1, size100kB, submission_datestr(datetime.now()), )) slint.callback(global_namePrinterQueue) def cancel_job(self, index): del self.printer_queue[index]对照.slint侧声明MainWindow内的callback quit();printerdemo.slint由窗口的关闭按钮触发Python 回调中调用self.hide()隐藏窗口hide方法见 api/python/slint/slint/slint.pyi全局对象PrinterQueue声明的callback start-job(string)与callback cancel-job(int)printer_queue.slint在 Python 侧用slint.callback(global_name..., name...)指明挂载的全局对象与回调名。用户点击添加打印任务时UI 调用PrinterQueue.start-job(title)事件便流入 Python 的push_job点击删除则触发cancel_job按索引移除队列项。这就是 Slint 混合开发的完整数据流闭环UI 声明数据与事件 → Python 填充模型并绑定回调 → 用户操作通过回调回流 → Python 修改模型驱动 UI 刷新。九、国际化gettext 与 init_translationsPrinter Demo 还演示了 Slint Python 绑定的国际化能力。.slint中所有面向用户的字符串都包裹在tr(...)中如title: tr(Slint printer demo)、tr(Printing Queue)这些字符串会由仓库工具提取为翻译模板。main.py 中语言切换回调定义如下slint.callback(global_namePrinterSettings) def change_language(self, language: int) - None: def load_translation(language: str) - typing.Optional[gettext.GNUTranslations]: translations_dir os.path.join(os.path.dirname(__file__), .., lang) try: return gettext.translation(printerdemo, translations_dir, [language]) except Exception: return None if language 0: translations load_translation(en) elif language 1: translations load_translation(fr) else: return slint.init_translations(translations)它对接的是.slint中PrinterSettings全局对象声明的callback change-language(int)见 demos/printerdemo/ui/pages/settings_page.slintUI 中通过PrinterSettings.change_language(index)在选择语言下拉框时触发。逻辑要点翻译文件布局gettext.translation(printerdemo, ...)会在lang/目录下查找LC_MESSAGES/printerdemo.mo。仓库中已提供法语翻译 demos/printerdemo/lang/fr/LC_MESSAGES.mo二进制编译产物由.po源文件经msgfmt生成索引映射整数参数 0 对应英语、1 对应法语其余值直接返回避免无效状态运行时生效slint.init_translations(translations)将gettext.GNUTranslations对象注入绑定层该 API 声明见 api/python/slint/slint/slint.pyi 的init_translations实现位于 api/python/slint/slint/init.py此后所有tr()字符串即时按新语言重新求值无需重启应用。十、仓库导航与延伸阅读围绕 Python 版 Printer Demo可以从以下路径继续深入demos/printerdemo/python/main.pyPython 业务逻辑全文模型初始化、定时器、回调、翻译demos/printerdemo/python/pyproject.tomluv 项目配置与本地 slint 依赖声明demos/printerdemo/ui/printerdemo.slint根窗口与页面切换骨架demos/printerdemo/ui/pages/printer_queue.slint队列数据结构、全局对象、进度条与列表组件demos/printerdemo/ui/pages/settings_page.slint设置页与语言切换入口demos/printerdemo/ui/pages全部页面组件复印、扫描、打印、墨水、USB 等demos/printerdemo/lang/fr/LC_MESSAGES法语翻译资源目录api/python/slint/slint/slint.pyi 与 api/python/slint/slint/init.pyPython 绑定的类型签名与实现可查阅ListModel、Timer、init_translations、ComponentInstance等全部公开 API。小结从uv run main.py一行命令启动到ListModel接管只读 mock 数据、Timer模拟打印进度、slint.callback回流用户事件、再到 gettext 与init_translations实现运行时语言切换Python 版 Printer Demo 完整展示了 Slint 声明式 UI 与 Python 逻辑协作的标准姿势。理解这一套模型注入 回调绑定 翻译注入的模式后你便可以将它复用到任何需要 Python 驱动 Slint 界面的真实项目中。【免费下载链接】slintSlint is an open-source declarative GUI toolkit to build native user interfaces for Rust, C, JavaScript, or Python apps.项目地址: https://gitcode.com/GitHub_Trending/sl/slint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考