diff --git a/SKILL.md b/SKILL.md index 628152d..35eeb8e 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,6 +1,6 @@ --- name: win-ui-ux-design -description: 为 WinUI 3、Windows App SDK、XAML、Fluent Design,以及使用 PySide 或 PyQt 面向 Windows 的 Qt for Python 应用设计、评审和实现专业的 Windows 桌面端 UI/UX。当任务涉及 Windows 桌面应用外壳或界面、PySide6、PyQt6、PySide2、PyQt5、Qt Widgets、QML、导航与窗口化、标题栏、NavigationView 或框架等价控件选择、响应式 XAML 或 Qt 布局、主题资源、QPalette 或 QSS、Mica 或 Acrylic、键盘/鼠标/触控交互、无障碍、设计系统规范、UI 审查,或将设计转换为 WinUI 3、PySide 或 PyQt 代码时使用。 +description: 为 WinUI 3、Windows App SDK、XAML、Fluent Design,以及使用 PySide 或 PyQt 面向 Windows 的 Qt for Python 应用设计、评审和实现专业的 Windows 桌面端 UI/UX。当任务涉及 Windows 桌面应用外壳或界面、PySide6、PyQt6、PySide2、PyQt5、Qt Widgets、QML、导航与窗口化、标题栏、NavigationView 或框架等价控件选择、响应式 XAML 或 Qt 布局、主题资源、QPalette 或 QSS、Mica 或 Acrylic、HTML 交互原型、客户评审与设计确认、键盘/鼠标/触控交互、无障碍、设计系统规范、UI 审查,或将已确认的设计转换为 WinUI 3、PySide 或 PyQt 代码时使用。 --- # Windows 桌面端 UI/UX 设计 @@ -10,13 +10,15 @@ description: 为 WinUI 3、Windows App SDK、XAML、Fluent Design,以及使用 ## 遵循核心规则 - 先优化用户任务流程,再设计单个控件的样式。 -- 优先使用 WinUI 控件、系统资源和内置交互行为,再考虑创建自定义 UI。 +- 优先使用所选框架的标准控件、系统资源和内置交互行为,再考虑创建自定义 UI。 - 将键盘、指针、触控、屏幕阅读器、缩放、主题和高对比度视为同一体验,而不是后期适配项。 - 定义每个有意义的状态:默认、悬停、按下、焦点、选中、禁用、加载、空、错误、离线或不可用、成功,以及适用时的撤销。 - 使用语义化 Token 和主题资源。不得只用颜色表达含义,也不得假设浅色模式的配色可直接用于深色模式。 - 保持适合桌面工作的界面密度。不要放大移动端模式,也不要把常用命令隐藏在仅触控手势中。 -- 根据项目的 Windows App SDK 版本、目标操作系统、打包模型和依赖项,对每个 API、控件和 Toolkit 建议设置版本门槛。 +- 根据项目的框架与绑定版本、目标操作系统、打包模型和依赖项,对每个 API、控件和 Toolkit 建议设置版本门槛。 - 区分 WinUI 3(`Microsoft.UI.Xaml`)与 UWP/WinUI 2(`Windows.UI.Xaml`)。未经验证不得跨框架复制 API。 +- 区分 PySide 与 PyQt,以及 Qt Widgets 与 QML。不要在同一应用中混用绑定,也不要把 WinUI 控件名直接写入 Qt 实现。 +- 将 HTML 原型视为可交互的设计规格和客户确认媒介,不视为最终桌面实现或原生行为证明。 ## 执行工作流 @@ -30,30 +32,48 @@ description: 为 WinUI 3、Windows App SDK、XAML、Fluent Design,以及使用 - 预期窗口尺寸、多窗口行为,以及调整大小和贴靠场景; - 主要输入方式,以及是否需要针对触控优化; - 品牌约束、浅色/深色行为和现有设计 Token。 +- 客户确认范围、原型保真度、交付方式、审批人和变更流程。 如果信息缺失,明确说明保守假设,并让版本敏感的建议保持条件化。 -### 2. 建模体验 +### 2. 选择框架路线 + +先根据实际依赖选择且只选择一条实现路线: + +- **WinUI 3:** 使用 `Microsoft.UI.Xaml`,并读取 [controls-and-patterns.md](references/controls-and-patterns.md) 与 [engineering-validation.md](references/engineering-validation.md)。 +- **PySide/PyQt:** 确认 PySide6、PyQt6 或遗留 Qt 5 绑定,再确定 Qt Widgets 或 QML;读取 [qt-pyside-pyqt.md](references/qt-pyside-pyqt.md),不要生成 XAML 或 WinUI API。 + +两条路线都必须读取 Windows 视觉基础与输入/无障碍基线。框架未知时先检查项目文件和导入语句,不要同时给出两套混杂实现。 + +### 3. 建模体验 定义主要用户任务、信息层级、窗口图、导航模型和命令界面。保持顶级导航浅而清晰。确定哪些工作应放在主窗口、辅助窗口、内联界面、浮出控件或模态对话框中。 -先描述顺利路径和恢复路径,再制作原型或 XAML。在导航、调整大小、刷新和错误发生时保留用户上下文。 +先描述顺利路径和恢复路径,再制作原型或所选框架的界面代码。在导航、调整大小、刷新和错误发生时保留用户上下文。 -### 3. 定义视觉系统 +### 4. 定义视觉系统 为字体、间距、几何、颜色、层级、材质、图标和动效建立精简的语义系统。除非品牌需要有意偏离,否则使用 Windows 默认规范。阅读 [windows-foundations.md](references/windows-foundations.md),了解当前 Fluent 原则、响应式断点、主题、材质和动效指南。 -### 4. 将意图映射到控件和模式 +### 5. 将意图映射到控件和模式 -根据交互语义选择控件,而不是根据外观或任意的项目数量阈值。跨菜单、工具栏、上下文菜单和快捷键复用命令。选择导航、集合、表单、设置、反馈或数据表格模式前,阅读 [controls-and-patterns.md](references/controls-and-patterns.md)。 +根据交互语义选择控件,而不是根据外观或任意的项目数量阈值。跨菜单、工具栏、上下文菜单和快捷键复用命令。WinUI 项目读取 [controls-and-patterns.md](references/controls-and-patterns.md);PySide/PyQt 项目读取 [qt-pyside-pyqt.md](references/qt-pyside-pyqt.md) 中的 Qt 控件映射。 -### 5. 规定交互与无障碍 +### 6. 规定交互与无障碍 -记录焦点顺序、方向键行为、访问键、快捷键、指针提示、上下文菜单、触控目标、拖拽替代方式、无障碍名称、状态播报、对比度和缩放。阅读 [input-accessibility.md](references/input-accessibility.md),了解必需的交互与无障碍基线。 +记录焦点顺序、方向键行为、访问键、快捷键、指针提示、上下文菜单、触控目标、拖拽替代方式、无障碍名称、状态播报、对比度和缩放。阅读 [input-accessibility.md](references/input-accessibility.md),了解必需的交互与无障碍基线。该参考中的 `AutomationProperties` 仅适用于 WinUI;PySide/PyQt 项目必须使用 [qt-pyside-pyqt.md](references/qt-pyside-pyqt.md) 中的 Qt Accessibility 映射。 -### 6. 工程实现与验证 +### 7. 制作 HTML 原型并取得确认 -请求实现时,遵循现有架构,并集中管理 Token、命令和状态。保留虚拟化,避免在 UI 线程上执行同步工作。阅读 [engineering-validation.md](references/engineering-validation.md),了解版本门槛、实现实践、性能检查和测试矩阵。 +对于新产品、主要页面或显著改版,在正式桌面实现前制作可本地运行的 HTML/CSS/JavaScript 交互原型。它必须复用已定义的 Token、内容、状态矩阵和窗口断点,覆盖主流程、关键异常和空/加载/禁用状态,而不接入生产后端。 + +向客户明确浏览器与 WinUI/Qt 在原生控件、窗口管理、字体渲染、系统材质、DPI、无障碍和性能上的差异。以书面验收清单确认信息架构、布局、视觉、文案、流程和状态;记录未确认项与不在原型验收范围内的原生能力。只有确认后才进入桌面实现。小型局部修改可说明理由后跳过此门禁。 + +制作或评审原型时读取 [html-prototype-handoff.md](references/html-prototype-handoff.md),并在交接时建立 HTML 组件到 WinUI 或 Qt 控件的映射。客户要求改变已确认设计时,先更新原型和验收记录,再修改桌面实现。 + +### 8. 工程实现与验证 + +请求实现时,遵循现有架构,并集中管理 Token、命令和状态。保留虚拟化,避免在 UI 线程上执行同步工作。WinUI 项目读取 [engineering-validation.md](references/engineering-validation.md);PySide/PyQt 项目读取 [qt-pyside-pyqt.md](references/qt-pyside-pyqt.md) 中的 Qt 工程、线程、主题、部署和测试规范。 在真实的紧凑、中等和宽窗口宽度下验证结果,而不是只在全屏显示器分辨率下验证。 @@ -69,6 +89,7 @@ description: 为 WinUI 3、Windows App SDK、XAML、Fluent Design,以及使用 6. 交互与状态矩阵; 7. 无障碍要求; 8. 实现说明和验收检查。 +9. 需要客户确认时,提供可运行的 HTML 原型、确认清单和桌面控件映射。 对于评审,先按严重程度列出发现。每项发现都要指出受影响的界面或控件、用户影响、违反的 Windows 约定和具体修正方案。将正确性与无障碍缺陷同主观的视觉润色建议分开。 @@ -81,6 +102,11 @@ description: 为 WinUI 3、Windows App SDK、XAML、Fluent Design,以及使用 - 不要假设当前 WinUI 3 项目中存在已归档的 Windows Community Toolkit `DataGrid`。 - 不要把 Emoji 用作结构性界面图标;使用平台字形或一致的矢量图标集。 - 不要强制在所有表面使用 Acrylic。用材质表达层级,并提供可读的纯色回退方案。 -- 当标准控件已经公开准确的无障碍名称时,不要强制设置 `AutomationProperties.Name`;仅在缺少语义时显式添加名称。 +- WinUI 标准控件已经公开准确的无障碍名称时,不要强制设置 `AutomationProperties.Name`;Qt 项目使用对应的 Qt Accessibility API,并且只在缺少语义时显式添加名称。 - 不要默认确认每次删除。对频繁且可恢复的操作优先提供撤销;仅对代价高或不可逆的后果使用模态确认。 - 不要把单一窗口尺寸、主题、DPI、区域设置或输入方式硬编码为设计基线。 +- 不要在一个进程中混用 PySide 与 PyQt,也不要混用绑定特有的 `Signal`/`Slot` 与 `pyqtSignal`/`pyqtSlot` API。 +- 不要从工作线程直接读取或修改 `QWidget`、Qt Quick 场景或其他 GUI 对象;通过队列信号把数据结果送回 GUI 线程。 +- 不要把 QSS 当作完整 CSS,也不要让全局样式表覆盖系统主题、高对比度、焦点和禁用状态。 +- 不要把 HTML 原型的 DOM、CSS 或 Web 组件逐字移植为 WinUI/Qt 控件,也不要承诺浏览器原型能证明原生窗口行为、性能或无障碍结果。 +- 不要为了原型接入生产数据库、真实凭据或不可逆操作;默认使用可重置的模拟数据和本地交互。 diff --git a/agents/openai.yaml b/agents/openai.yaml index b634fce..862e0f2 100644 --- a/agents/openai.yaml +++ b/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Windows UI/UX 设计" - short_description: "设计、评审并实现专业的 Windows 桌面端体验" - default_prompt: "使用 $win-ui-ux-design 设计并评审 Windows 桌面应用体验。" + short_description: "设计、原型确认并实现 Windows 桌面端体验" + default_prompt: "使用 $win-ui-ux-design 设计 Windows 桌面应用,先制作 HTML 交互原型供客户确认,再按项目实际采用 WinUI、PySide 或 PyQt 实现。" diff --git a/references/html-prototype-handoff.md b/references/html-prototype-handoff.md new file mode 100644 index 0000000..935b399 --- /dev/null +++ b/references/html-prototype-handoff.md @@ -0,0 +1,132 @@ +# HTML 原型评审与桌面实现交接 + +## 目录 + +1. 适用范围与目标 +2. 原型前的设计冻结条件 +3. 原型技术与目录约束 +4. 必须覆盖的内容与状态 +5. 客户评审与验收边界 +6. 从 HTML 交接到 WinUI 或 Qt +7. 变更管理与完成标准 +8. 常见反模式 + +## 1. 适用范围与目标 + +HTML 原型用于低成本验证信息架构、内容层级、视觉 Token、窗口断点、关键流程和状态反馈。它是设计规格的可交互表达,不是最终产品的 Web 版本。 + +以下情况默认制作原型: + +- 新产品、主要窗口、关键业务流程或显著视觉改版; +- 客户需要在原生开发前确认范围、流程或视觉; +- 多角色、多状态或跨页面交互仅靠静态图难以说明; +- WinUI、PySide/PyQt 团队需要统一实现基准。 + +仅修正文案、颜色、间距或单个明确控件时,可以说明理由后跳过。跳过不等于省略状态、无障碍和验收要求。 + +## 2. 原型前的设计冻结条件 + +开始写 HTML 前至少确定: + +- 目标用户、核心任务和主流程; +- 页面/窗口清单、导航模型和命令层级; +- 目标桌面框架与控件映射方向; +- 字体、颜色、间距、圆角、层级和动效 Token; +- 紧凑、中等、宽窗口的布局策略; +- 加载、空、错误、离线、禁用、成功、取消和撤销状态; +- 原型要确认的决策、审批人和反馈截止方式。 + +仍有未知项时在原型内显式标注假设,不要用精致视觉掩盖未完成的产品决策。 + +## 3. 原型技术与目录约束 + +默认创建独立的 `prototype/` 目录,至少包含入口 HTML、样式、交互脚本和本地资源。项目已有前端原型栈时遵循现有结构;没有时优先使用简单、可直接打开或通过轻量本地服务器运行的 HTML/CSS/JavaScript。 + +- 默认不引入前端框架、构建链或组件库;只有复杂状态确有收益且团队能维护时才使用。 +- 不依赖外部 CDN、在线字体、远程图片或只有开发机可用的绝对路径。 +- 使用语义化 HTML、CSS 自定义属性和少量模块化 JavaScript,保持客户环境可重复运行。 +- 将设计 Token 集中定义,避免在各页面复制颜色、间距和字号。 +- 使用本地模拟数据或可重置 fixture;需要模拟接口时明确 schema、延迟、空数据和失败响应。 +- 不包含生产凭据、真实个人数据、生产数据库连接、遥测或不可逆操作。 +- 提供清晰的启动入口;不得要求客户先理解桌面工程的构建环境。 + +原型不是生产 Web 应用,不要提前建设路由框架、认证、完整后端、SEO、服务端渲染或发布基础设施,除非这些本身就是待确认体验的一部分。 + +## 4. 必须覆盖的内容与状态 + +至少实现: + +- 主导航、页面层级和主要任务的端到端可点击路径; +- 关键命令、菜单、对话框、表单验证、选择和反馈; +- 默认、悬停、按下、焦点、选中和禁用状态; +- 加载、空、错误、成功、取消、超时和过期结果; +- 紧凑、中等、宽窗口的重排、折叠和滚动行为; +- 浅色、深色,以及适用时的高对比度近似方案; +- 键盘焦点顺序、Enter/Escape、常用快捷键和不依赖悬停的操作入口; +- 真实长度的中文、数字、日期、错误文案和高密度示例数据。 + +避免只有首页和理想数据的“演示动画”。客户需要看到业务完成条件、失败后的恢复方式以及删除等高风险操作的后果。 + +## 5. 客户评审与验收边界 + +评审前提供场景脚本,而不是只给一个 URL 或目录。按用户任务引导客户检查并记录: + +1. 信息架构和功能范围; +2. 页面布局、密度和窗口断点; +3. 品牌、颜色、字体、图标和动效方向; +4. 文案、术语、数据字段和默认值; +5. 主流程、异常流程、权限和不可用状态; +6. 哪些内容已确认、需修改、暂缓或超出范围。 + +必须声明以下内容不能仅靠 HTML 验收: + +- 原生标题栏、系统菜单、Snap Layouts、多窗口和任务栏行为; +- WinUI/Qt 控件的精确尺寸、字体栅格化和系统主题差异; +- Mica/Acrylic、原生弹出层、输入法和多显示器 DPI 行为; +- Narrator/UI Automation/Qt Accessibility 的最终语义; +- 启动速度、内存、虚拟化、线程、打包、升级和生产数据性能。 + +验收记录至少包含原型版本或提交、日期、审批人、确认项、遗留项和明确排除项。未回复不能自动视为确认。 + +## 6. 从 HTML 交接到 WinUI 或 Qt + +确认后冻结原型版本,并建立追踪表: + +| 原型项 | 设计 Token/状态 | WinUI 实现 | Qt Widgets/QML 实现 | 差异与验证 | +|---|---|---|---|---| +| 导航 | 层级、选中、折叠 | `NavigationView` 等 | `QListView` + 页面容器等 | 键盘、窗口断点 | +| 共享命令 | 文本、图标、启用状态 | `XamlUICommand`/命令 | `QAction` | 快捷键、上下文 | +| 数据集合 | 空、加载、选择、分页 | 虚拟化集合控件 | Model/View | 大数据性能 | +| 对话与反馈 | 模态性、默认操作 | `ContentDialog`/信息条 | `QDialog`/语义 Banner | 焦点、Escape | + +交接时遵循以下规则: + +- 复用设计 Token 和状态名称,不复用 DOM 结构或逐字翻译 CSS。 +- 把模拟数据 schema 转成明确的领域模型、接口契约和错误类型。 +- 将 JavaScript 交互意图映射到桌面命令、信号/事件和状态管理。 +- 选择目标框架的标准控件;原型视觉与原生行为冲突时优先保证任务、可用性和平台约定。 +- 对无法一比一实现的材质、布局或动效给出差异说明,并在桌面端验收中重新确认。 +- 桌面实现完成后执行视觉对照,也必须单独完成原生键盘、无障碍、DPI、性能和打包测试。 + +## 7. 变更管理与完成标准 + +客户确认后的需求变化先回到原型和验收记录。评估它对页面、状态、数据契约、桌面控件、开发量和测试范围的影响,再更新原生实现。 + +HTML 原型阶段完成必须同时满足: + +- 评审范围内流程和关键状态可操作; +- 指定窗口宽度、主题和键盘路径已检查; +- 不含真实凭据和生产副作用; +- 客户能按说明独立运行; +- 已形成书面确认、遗留项和排除项; +- 已建立到 WinUI 或 Qt 的控件与状态映射。 + +## 8. 常见反模式 + +- 先写完整 HTML,再补用户流程、状态和验收目标。 +- 为一次性原型引入复杂前端框架、后端和部署平台。 +- 只实现理想路径,使用 `alert()` 代替真实错误、确认和恢复体验。 +- 用浏览器窗口模拟原生标题栏后承诺 Snap、系统菜单或窗口拖拽效果。 +- 把浏览器像素截图作为所有 DPI、主题和字体环境的最终标准。 +- 客户口头说“差不多”便开始开发,没有版本化确认和遗留项。 +- 桌面端直接复制 HTML 的控件结构、CSS 数值或 JavaScript 状态管理。 diff --git a/references/qt-pyside-pyqt.md b/references/qt-pyside-pyqt.md new file mode 100644 index 0000000..5982403 --- /dev/null +++ b/references/qt-pyside-pyqt.md @@ -0,0 +1,262 @@ +# Windows 上的 PySide/PyQt 工程指南 + +## 目录 + +1. 确认绑定与 UI 技术 +2. 将 Windows 交互意图映射到 Qt +3. 架构、对象生命周期与数据模型 +4. 布局、窗口化与高 DPI +5. 主题、QSS、图标与 Windows 材质 +6. 命令、键盘与无障碍 +7. 线程、异步与响应速度 +8. Designer、资源、设置与本地化 +9. 部署与测试 +10. 常见反模式 +11. 交付检查清单 +12. 官方资料 + +## 1. 确认绑定与 UI 技术 + +先检查 `pyproject.toml`、锁文件、requirements、导入语句和实际安装版本,再生成代码。 + +### 选择绑定 + +- 新项目优先选择 Qt 6 绑定,除非插件、操作系统或现有代码明确要求 Qt 5。 +- PySide6 是 Qt 官方 Python 绑定,采用 LGPLv3/GPLv3/商业许可组合;发布前确认应用对 Qt 许可义务的满足方式。 +- PyQt6 采用 GPLv3 或 Riverbank 商业许可,不提供 LGPL;闭源分发前必须确认许可方案。 +- 维护现有 PySide2/PyQt5 项目时遵循项目版本,不要在 UI 改造中顺带升级主版本。 +- 不要在一个进程或分发包中混用 PySide 与 PyQt。第三方组件的绑定必须与应用一致。 + +### 选择 UI 技术 + +| 场景 | 优先选择 | +|---|---| +| 高密度生产力工具、表格、菜单、工具栏、停靠面板 | Qt Widgets | +| 既有 `.ui` 文件或大量成熟 QWidget 控件 | Qt Widgets | +| 高度定制的视觉、连续动画、触控优先界面 | Qt Quick/QML | +| Widgets 与 QML 混合 | 仅在价值明确时采用,并定义边界、线程、焦点和无障碍责任 | + +不要把 Qt Quick 仅当作“更现代的 Widgets”,也不要为了原生外观强行用 Widgets 实现复杂动画。根据任务、团队能力、组件生态、性能、部署和无障碍要求选择。 + +### 保持绑定 API 一致 + +- PySide 使用 `Signal`、`Slot`、`Property`;PyQt 使用 `pyqtSignal`、`pyqtSlot`、`pyqtProperty`。 +- PySide 项目仅在项目已统一启用时使用 `snake_case` 或 `true_property` 特性;不要与默认 camelCase 风格随机混用。 +- 生成示例时沿用仓库现有导入风格、枚举写法和 UI 构建方式。 + +## 2. 将 Windows 交互意图映射到 Qt + +根据语义选择控件,不要逐字翻译 WinUI 控件名: + +| Windows/WinUI 意图 | Qt Widgets 实现 | 说明 | +|---|---|---| +| 应用主窗口 | `QMainWindow` + `centralWidget` | 可组合菜单栏、工具栏、状态栏和停靠面板 | +| 顶级导航 | 带 Model 的 `QListView` + `QStackedWidget` | 小型静态同级页也可用 `QTabWidget`;导航必须有文本标签 | +| 文档标签页 | `QTabWidget` 或 `QTabBar` + 内容容器 | 定义关闭、重排、未保存和快捷键行为 | +| 辅助工作面板 | `QDockWidget` | 定义允许区域、浮动、关闭和状态恢复 | +| 分栏工作区 | `QSplitter` | 设置合理最小尺寸与折叠行为 | +| 页面级命令 | `QAction` + `QToolBar`/按钮 | 同一 `QAction` 复用于菜单、工具栏和快捷键 | +| 应用菜单 | `QMenuBar`、`QMenu`、`QAction` | 使用标准菜单分组和角色 | +| 上下文命令 | `QMenu` 或 `QAction` 集合 | 同时提供可见或键盘访问路径 | +| 列表 | `QListView` + `QAbstractListModel` | 动态或大型数据不要依赖 `QListWidget` | +| 表格 | `QTableView` + `QAbstractTableModel` | 排序/筛选使用 `QSortFilterProxyModel` | +| 树 | `QTreeView` + `QAbstractItemModel` | 保持展开、选择和键盘行为 | +| 简单表单 | `QFormLayout` + 标准输入控件 | 设置标签 Buddy、验证和错误位置 | +| 模态任务 | `QDialog` + `QDialogButtonBox` | 仅用于真正需要阻塞的决策或短任务 | +| 简单系统消息 | `QMessageBox` | 不要用于频繁状态或长文本工作流 | +| 内联信息条 | 自定义语义化 Banner `QWidget` | 包含图标、文本、操作和关闭入口,不要用状态栏替代关键错误 | +| 确定进度 | `QProgressBar` | 提供取消、失败和完成状态 | +| 阻塞进度 | `QProgressDialog` | 仅在确实需要窗口级阻塞时使用 | +| 持久设置 | `QSettings` | 先设置组织名和应用名,定义迁移与默认值 | + +Qt Quick/QML 项目使用 Qt Quick Controls 的等价语义控件,并为 Python 暴露的状态使用 `Signal`、`Slot` 和带通知信号的 `Property`。不要把 QWidget 嵌入 QML 作为常规布局方案。 + +## 3. 架构、对象生命周期与数据模型 + +### 对象与职责 + +- 让 View 负责渲染和输入转发,让领域/应用服务负责业务规则、I/O 和持久化。 +- 使用 `QObject` 的父子所有权管理 Qt 对象生命周期;不要同时建立不必要的 Python 强引用环。 +- 对需要延迟销毁的 `QObject` 使用 `deleteLater()`,尤其是跨事件循环或线程退出时。 +- 将共享用户操作建模为 `QAction`,避免在多个按钮和菜单处理器中复制逻辑。 +- 在关闭窗口前处理未保存更改,但不要把业务保存逻辑塞入 `closeEvent()`。 + +### 信号与槽 + +- PySide 类中将作为连接目标的方法标记为 `@Slot(...)`;官方建议这样做以减少运行时开销,并正确表达线程亲和性。 +- 让信号载荷传递不可变数据、标识符或轻量结果,不要跨线程传递需要在工作线程访问的 GUI 对象。 +- 明确连接的所有者和断开时机,避免重复连接导致一次操作执行多次。 +- QML 可见属性必须提供通知信号,否则绑定不会可靠更新。 + +### Model/View + +- 动态、共享、可排序筛选或可能变大的数据使用 `QListView`、`QTableView`、`QTreeView` 与 `QAbstractItemModel` 派生模型。 +- 一维和二维数据分别优先从 `QAbstractListModel`、`QAbstractTableModel` 开始,不要无必要直接实现完整 `QAbstractItemModel`。 +- 使用 `QSortFilterProxyModel` 处理排序和筛选,不要为每次查询复制整个源数据集合。 +- 插入、删除、移动和重置模型时使用正确的 begin/end 通知;不得只修改 Python 列表后强制刷新视图。 +- 自定义绘制和编辑使用 `QStyledItemDelegate`;不要为每个单元格创建常驻 QWidget。 +- `QListWidget`、`QTableWidget`、`QTreeWidget` 仅适合小型、简单、不会共享模型的数据。 + +## 4. 布局、窗口化与高 DPI + +### 布局 + +- 使用 `QLayout` 派生布局、`QSizePolicy`、stretch、`sizeHint()` 和最小尺寸,不要用 `setGeometry()` 手工排列常规界面。 +- 需要随宽度换行的自定义控件实现合理的 `heightForWidth()`;内容变化时调用 `updateGeometry()`。 +- 为窗口定义可用的最小尺寸,而不是固定尺寸。长文本、翻译和字体放大后仍应可操作。 +- 在少量语义断点下重排或显示/隐藏次要面板;不要在每次 `resizeEvent()` 中重建整棵 Widget 树。 +- 响应式切换时保留焦点、选择、滚动、编辑和展开状态。 + +### 主窗口与窗口状态 + +- `QMainWindow` 只把一个控件设置为 `centralWidget`,再通过 Qt 提供的 API 管理菜单栏、工具栏、状态栏和 `QDockWidget`。 +- 使用 `saveGeometry()`/`restoreGeometry()` 和 `QMainWindow.saveState()`/`restoreState()` 持久化窗口与停靠布局。 +- 恢复窗口时检查当前屏幕可用区域,防止窗口因显示器移除或 DPI 变化而出现在屏幕外。 +- 为辅助窗口定义所有者、模态性、任务栏显示、激活、关闭和共享数据生命周期。 +- 优先保留原生窗口框架。无边框窗口需要自行正确实现缩放命中测试、拖动、系统菜单、标题按钮、Snap Layouts、高 DPI 和无障碍,除非产品价值足以承担成本,否则不要使用。 + +### 高 DPI 与多显示器 + +- Qt 6 以设备无关像素描述大多数 Widget、Quick、事件和窗口几何;不要再次手工乘系统缩放比例。 +- 自定义像素绘制或图像几何时读取 `devicePixelRatio()`;不要把物理像素当作布局单位。 +- 使用 SVG、`QIcon` 多尺寸资源或 `@2x` 高分辨率资源。验证 100%、125%、150%、200% 以及跨显示器移动。 +- 屏幕几何使用 `QScreen` 的设备无关坐标;不要假设多个屏幕组成无间隙的物理像素网格。 + +## 5. 主题、QSS、图标与 Windows 材质 + +### 主题优先级 + +1. 优先让 `QStyle` 和系统 `QPalette` 提供平台行为与控件状态。 +2. 用语义 Token 生成有限的自定义 `QPalette` 或组件级 QSS。 +3. 只有品牌需要时才替换标准控件绘制或实现自定义 `QStyle`。 + +`QPalette` 为活动、非活动和禁用状态提供颜色组。覆盖颜色时同时定义这些状态,并独立验证浅色、深色和高对比度。 + +Qt 6.5 或更高版本可通过 `QGuiApplication.styleHints().colorScheme()` 读取系统配色方案,并监听 `colorSchemeChanged`。处理主题变化时也要响应 `QEvent.PaletteChange` 或 `QEvent.ApplicationPaletteChange`。使用前检查项目 Qt 版本;较旧版本不得生成不存在的 API。 + +Qt 6.10 或更高版本提供更多平台无障碍提示;低版本仍必须通过实际 Windows 高对比度测试验证,而不是自行猜测系统颜色。 + +### QSS + +- QSS 不是完整 CSS:不要期待 Web 布局、CSS 变量、继承和选择器行为完全一致。 +- 避免 `QWidget { ... }` 等大范围规则覆盖所有标准状态。 +- 为 hover、pressed、checked、selected、disabled、focus、active/inactive 和高对比度定义可辨识行为。 +- 使用动态属性选择器时,属性变化后按项目需要重新 polish;不要依赖偶然刷新。 +- 样式表可能改变原生绘制和尺寸提示。修改后重新测试菜单、滚动条、输入法、焦点框、停靠窗口和高 DPI。 + +### 图标与 Windows 材质 + +- 使用一致的 SVG/`QIcon` 资源,为 normal、disabled、active、selected 等模式提供可读变体。 +- 不要用 Emoji 作为结构图标,也不要依赖某台开发机才存在的字体图标。 +- Qt Widgets/PySide 没有与 WinUI `MicaBackdrop` 完全等价的跨版本 API。需要 Mica/Acrylic 时,把 Windows 原生集成隔离为可选适配层,按 Windows/Qt 版本检查,并始终提供纯色 `QPalette` 回退。 +- 不要为装饰效果移除原生标题栏、破坏高对比度或引入不可维护的全局事件过滤器。 + +## 6. 命令、键盘与无障碍 + +### 命令与键盘 + +- 用 `QAction` 集中管理文本、图标、启用/选中状态和快捷键,并复用于菜单、工具栏、按钮或上下文菜单。 +- 标准操作优先使用 `QKeySequence.StandardKey`,避免硬编码与平台约定冲突的组合键。 +- 使用 `QShortcut` 时设置合适的 `Qt.ShortcutContext`;不要让页面快捷键意外覆盖整个应用。 +- 使用标签中的 `&` 和 `QLabel.setBuddy()` 提供访问键。处理中文界面时仍要检查访问键是否重复和是否可发现。 +- 优先使用自然 Tab 顺序,仅在布局顺序无法表达正确流程时使用 `QWidget.setTabOrder()`。 +- 所有悬停、右键和拖拽加速操作都必须有可见或键盘等价路径。 + +### 无障碍 + +- 标准 Widgets 与 Qt Quick Controls 已提供基础无障碍接口,优先复用它们。 +- 仅在可见文本无法形成正确名称时设置 `accessibleName`;把补充说明放入 `accessibleDescription`。 +- 为表单建立标签 Buddy 和合理焦点顺序;不要只通过占位符标识输入字段。 +- 自定义 QWidget 需要公开正确角色、名称、状态、值、操作和事件;复杂控件根据需要实现 `QAccessibleInterface`/`QAccessibleWidget`。 +- QML 自定义项使用 `Accessible` 附加属性公开角色、名称、描述和操作。 +- 用 Narrator、Accessibility Insights/Inspect、键盘、高对比度和文本/显示缩放验证真实体验。 + +## 7. 线程、异步与响应速度 + +### GUI 线程规则 + +- `QWidget` 及其子类不是可重入对象,只能在 GUI 主线程创建和访问。Qt Quick 场景对象也不得从工作线程直接修改。 +- 后台工作使用 worker `QObject` + `moveToThread()`,或 `QThreadPool` + `QRunnable`;根据项目复杂度选择一种模式并统一。 +- 通过默认 AutoConnection 或显式 QueuedConnection 的信号把结果送回 GUI 线程。 +- 对具有事件循环的接收者使用绑定对应的 Slot 装饰器,确保代码在接收对象所属线程执行。 +- 在线程退出时使用 `quit()`、`wait()` 和 `deleteLater()` 建立明确的清理链;关闭窗口后不得让回调访问已销毁 UI。 +- 不要对同一线程使用 BlockingQueuedConnection,这会导致死锁。 + +### 任务设计 + +- 长任务提供进度、取消和最终状态;取消必须检查任务是否仍可安全提交结果。 +- 搜索、预览和重新加载使用请求 ID 或取消令牌忽略过期结果。 +- 网络请求优先使用事件驱动的 `QNetworkAccessManager`,或在工作线程使用不会触碰 GUI 的客户端。 +- 不要在槽函数中执行阻塞 I/O,也不要用频繁 `processEvents()` 掩盖冻结。 +- 需要 `asyncio` 时沿用项目已有事件循环集成。采用 `PySide6.QtAsyncio` 前核对精确版本和支持范围,不要同时运行两个互相竞争的主事件循环。 + +## 8. Designer、资源、设置与本地化 + +- Qt Widgets Designer 生成的 `.ui` 文件应通过 `pyside6-uic`/`pyuic6` 生成代码,或由项目统一使用 `QUiLoader` 运行时加载。 +- 不要手工编辑生成的 `ui_*.py`;在继承/组合的业务类中扩展界面,重新生成时避免丢失修改。 +- PySide 官方建议优先使用与绑定版本匹配的 `pyside6-uic`,避免直接调用不匹配的独立 `uic`。 +- 使用 `.qrc` 与 `pyside6-rcc`/对应 PyQt 工具管理图标和资源,或采用项目已经验证的包资源方案。 +- 使用 `QSettings` 前设置组织名、域和应用名;为设置键、默认值、版本迁移和损坏恢复建立规范。 +- 使用 `tr()`/翻译上下文和 `QTranslator` 进行本地化。不要拼接句子;测试复数、快捷键、长文本和从右到左布局。 + +## 9. 部署与测试 + +### 部署 + +- 固定 Python、绑定、Qt 和打包工具版本,并在干净虚拟环境中构建。 +- PySide6 优先评估官方 `pyside6-deploy`;它使用 `pysidedeploy.spec` 保存配置,并支持 `--dry-run` 查看实际命令。 +- PyQt 使用项目许可和工具链已验证的打包方案;不要把 PySide 部署命令用于 PyQt。 +- 检查 Qt 平台插件、图像格式插件、QML imports、翻译、OpenSSL/多媒体依赖、MSVC Runtime、应用图标和资源是否完整。 +- 在干净 Windows 虚拟机上测试首次启动、无开发环境运行、非 ASCII 路径、只读目录、多用户配置、升级与卸载。 +- 发布前确认代码签名、安装器、文件关联、协议处理、自动更新和许可文件要求。 + +### 测试 + +- 使用 Qt Test/QTest 或项目现有测试栈覆盖关键 Widget、快捷键、模型通知和信号行为。 +- 对 Model/View 测试插入、删除、移动、排序、筛选、编辑、空数据和超大数据。 +- 对线程测试取消、窗口提前关闭、过期结果、异常和应用退出。 +- 执行 Windows 测试矩阵:最低支持版本与当前 Windows 11;100%–200% 缩放;跨显示器;浅色、深色、高对比度;键盘、鼠标和声明支持的触控;Narrator。 +- 测试打包产物,而不只测试源码环境。 + +## 10. 常见反模式 + +- 在同一项目中混用 `PySide6` 与 `PyQt6` 导入。 +- 从工作线程调用 Widget 方法或把 Widget 传给 worker。 +- 用 `time.sleep()`、同步网络或大循环阻塞 GUI 线程。 +- 为动态表格使用 `QTableWidget` 并为每个单元格嵌入 Widget。 +- 在每次窗口调整大小时销毁并重建全部页面。 +- 用固定坐标、固定字体像素或手动 DPI 倍增代替 Qt 布局系统。 +- 用全局 QSS 抹掉原生焦点、禁用、选择、高对比度和非活动窗口状态。 +- 手工编辑 `pyside6-uic`/`pyuic6` 生成文件。 +- 无版本检查地复制 Qt C++、旧 PySide2、PyQt5 或另一个绑定的示例。 +- 为获得 Mica/Acrylic 无条件启用无边框窗口或私有 Windows API。 + +## 11. 交付检查清单 + +- [ ] 已确认绑定、精确版本、Qt Widgets/QML 路线和许可证。 +- [ ] 未混用 PySide/PyQt 或绑定特有 API。 +- [ ] 标准控件、Model/View、`QAction` 和布局系统得到优先使用。 +- [ ] GUI 对象只在主线程访问,后台结果通过队列信号返回。 +- [ ] 主题跟随系统,QSS 未破坏高对比度、焦点或禁用状态。 +- [ ] 窗口在调整大小、贴靠、跨显示器和 100%–200% 缩放时可用。 +- [ ] 键盘、上下文菜单、拖拽替代方式和无障碍语义完整。 +- [ ] 加载、空、错误、取消、超时、过期结果和撤销状态已处理。 +- [ ] Designer 生成代码、资源和设置具有可重复的生成/迁移流程。 +- [ ] 已在干净 Windows 环境测试最终打包产物。 + +## 12. 官方资料 + +- [Qt for Python / PySide6](https://doc.qt.io/qtforpython-6/) +- [PyQt 与许可](https://riverbankcomputing.com/software/pyqt) +- [PySide 信号与槽](https://doc.qt.io/qtforpython-6/tutorials/basictutorial/signals_and_slots.html) +- [Qt 线程与 QObject](https://doc.qt.io/qt-6/threads-qobject.html) +- [Qt Model/View 编程](https://doc.qt.io/qt-6/model-view-programming.html) +- [Qt Widgets 布局管理](https://doc.qt.io/qt-6/layout.html) +- [Qt 高 DPI](https://doc.qt.io/qt-6/highdpi.html) +- [QStyleHints 与系统配色](https://doc.qt.io/qt-6/qstylehints.html) +- [Qt 样式表参考](https://doc.qt.io/qt-6/stylesheet-reference.html) +- [Qt 无障碍](https://doc.qt.io/qt-6/accessible.html) +- [QWidget 应用无障碍](https://doc.qt.io/qt-6/accessible-qwidget.html) +- [PySide6 部署](https://doc.qt.io/qtforpython-6/deployment/index.html) +- [pyside6-deploy](https://doc.qt.io/qtforpython-6/deployment/deployment-pyside6-deploy.html) +- [pyside6-uic](https://doc.qt.io/qtforpython-6/tools/pyside-uic.html)