我要求你使用Qt Widget编写一个GUI程序。该GUI程序是wfassoc的一个可视化界面。wfassoc是一个由Rust编写,并暴露出C接口,可以操作Windows注册表,来管理应用程序的注册和卸载,以及文件关联的动态链接库。 我要求你在@example/qwfassoc/TASKS.md 中先做好详细的规划,而不是上来就写代码。我会安排其他人来负责执行你做的规划。 # 项目要求 - 使用Qt Widget编写界面,而不是QML。 - 使用UI文件而不是C++语句来构建界面。 - 我使用的是Qt 6,使用CMake作为构建系统,不要使用Qt的qmake。 - 使用toml11作为TOML读取库。 # 界面要求 这是一个基于 Qt Widgets 的标准对话框界面描述。你可以按照以下层级结构来构建代码: ## 主窗口容器 (Main Window) * 类: `QDialog`。 * 窗口标题: "xxx选项"。xxx在应用程序初始化时,通过wfassoc的Program提供的接口,运行时获取。 * 窗口图标:在应用程序初始化时,通过wfassoc的Program提供的接口,运行时获取。 * 大小限制:固定大小480x600 ## 选项卡 (Top Tabs) * 组件: `QTabWidget`。 * 标签页 (Tabs): 从左到右依次添加以下标签页: 1. 应用程序 2. 文件关联 * 大小:选项卡占据对话框全部内容 ## "应用程序"选项卡内容 该选项卡内部使用垂直布局 (`QVBoxLayout`),包含一个主要的分组区域: ### 区域内容 * 容器: `QGroupBox`。 * 区域标题:安装与卸载 * 布局: 垂直布局 (`QVBoxLayout`)。 * 上半部分 * 水平布局(`QHBoxLayout`)。 * 左侧: 一个 `QLabel` 显示图标,该图标表示要设定的应用程序的图标。在应用程序初始化时,通过wfassoc的Program提供的接口,运行时获取。 * 右侧: 一个 `QLabel` 显示文本"在此安装或卸载xxx",表示要设定的应用程序的名称。xxx在应用程序初始化时,通过wfassoc的Program提供的接口,运行时获取。 (文本需要设置自动换行 `setWordWrap(true)`)。 * 下半部分 * 水平布局(`QHBoxLayout`)。 * 内容为两个 `QPushButton`,文本分别为: * 安装:为当前对象(系统或当前用户,由应用程序初始化时从命令行参数获取)安装应用。如果应用程序已经安装,则不可点击。 * 卸载:为当前对象(系统或当前用户,由应用程序初始化时从命令行参数获取)卸载应用。如果应用程序没有安装,则不可点击。 ## "文件关联"选项卡内容 在这个选项页内部,使用一个垂直布局 (`QVBoxLayout`) 来排列以下控件: * 说明文本: * 组件: `QLabel`。 * 文本: "使用 xxx 关联的文件类型:"。xxx在应用程序初始化时,通过wfassoc的Program提供的接口,运行时获取。 * 功能按钮行: * 布局: `QHBoxLayout` (水平布局)。 * 组件: 两个 `QPushButton`。 * 文本: 两个按钮的文本都是 "+"。 * 位置: 位于列表上方,用于“全选”操作(第一次点击,将所有没关联的文件扩展名(显示为空白)设置为应用程序提供的打开方式。如果没有空白内容,或第二次点击,将所有文件全部设置为应用程序提供的打开方式)。 * 文件类型列表 (核心组件): * 组件: `QTableWidget` (表格控件)。 * 列数: 3列。 * 表头 (Header): * 第1列标题: "类型" * 第2列标题: "uuu" (uuu在运行时进行获取,为当前用户名) * 第3列标题: "所有用户" * 行内容示例: * 第一列:一个文件类型图标,右边跟着对应的文本。表示当前文件扩展名,和当前混合视图(hybrid)下的图标。图标和文本均从wfassoc函数获取。 * 第二列:用户视图(user)下的名称。文本从wfassoc函数获取。 * 第三列:系统视图(system)下的名称。文本从wfassoc函数获取。 * 滚动条: 右侧有一个垂直滚动条 (`QScrollBar`),表示内容超出可视区域。 * 操作方式: * 第二列和第三列的元素可点击。 * 如果元素为空白或其它打开方式,则点击后设置为当前应用程序指定的打开方式(link)。 * 如果是自身打开方式,点击后设置为空白(unlink) * 点击后,第一列的图标需要改变,也因此你需要暂存当前应用程序提供打开方式的图标。如果第二第三列均为空,则不显示图标(仍然占位,显示为空白)。 * 点击操作并不会实时操作注册表,程序需要暂存用户的需求,然后在点击确认或应用按钮后再统一执行。 * 底部按钮栏 * 布局: `QHBoxLayout` (水平布局),通常右对齐或使用 `QDialogButtonBox`。 * 组件: 三个 `QPushButton`。 * 按钮文本 (从左到右): 1. "确定" (通常设为默认按钮 `setDefault(true)`)。 2. "取消"。 3. "应用":点击后应用修改,并留在页面 (如果没有修改,则不可用)。 额外注意: * 如果应用程序没有安装,则本页面下所有内容均不启用。 * 如果启动时命令行指定以为当前用户安装的模式启动,则系统那一栏所有按钮都不可用 # 代码要求 - 有关wfassoc的接口,请查阅@wfassoc-cdylib/codegen/wfassoc++.h 我要求你使用这个头文件中提供的内容来进行编写。 - wfassoc++.h文件中没有注释,如果你想查看注释,请访问@wfassoc-cdylib/codegen/wfassoc.h 文件。wfassoc++.h是wfassoc.h的C++包装。 - wfassoc.h所暴露的接口是由Rust编写的,通常查看wfassoc.h可满足所有需求。如果仍有不确定的内容,可查看其对应Rust项目的源码,位于@wfassoc-cdylib/src 目录下。或更进一步地查看其依赖的源码,位于@wfassoc/src 目录下。 - 该GUI程序需要接受两个必要的命令行参数,请使用Qt内置的命令行解析器进行解析: - `-c`或`--manifest`:指定要配置的应用程序的清单文件。 - `-f`或`--for`:指定应用程序要安装到的 - 清单文件的样例是@example/manifest/ppic.toml - 在应用程序加载时,或者执行操作时,如果发生错误(例如底层wfassoc发生错误,丢失命令行选项等,则弹出对话框报错,然后立即退出程序) - 程序基本流程: - 接受命令行,检查命令行参数是否合法 - 加载命令行指定的manifest文件,并使用sanitizer检查错误。你可以阅读@wfassoc-exec/src/manifest.rs 文件来看看我是如何在Rust中检查它的。 - 按照给定的manifest文件,使用wfassoc库构建schema,然后再构建program。 - 初始化窗口。 - 调用wfassoc program提供的函数,检查应用程序是否安装,设置窗口的安装部分的按钮enable。 - 调用wfassoc program提供的函数,遍历所有文件扩展名和关联情况,设置窗口的文件关联表格。 - 用户可以在"应用程序"选项卡中注册和卸载应用程序,点击后弹出窗口表示安装或卸载成功,然后检测是否安装,并刷新各个控件的enable状态。 - 用户可以在"文件关联"选项卡中设置是否以当前应用程序打开某些扩展名。用户可以点击全选按钮或单元格来进行设置,应用程序暂存修改,等用户点击确认或应用后再应用修改。如果点击的是应用,则刷新当前页面。 # 额外要求 - 不要尝试去编译来检查错误。我会安排其他人来检查程序是否能正常运行,并汇报回来,你再修改。 - 你不需要关心能否找到Qt,wfassoc和toml11这些库。 - 对于wfassoc,你只需要将@wfassoc-cdylib/codegen/Findwfassoc.cmake 复制到@example/qwfassoc/cmake 目录下,并在此目录下编写一个README.md,表明这个文件是从哪里复制来的即可。然后把复制的cmake文件所在目录加入find_package目录,然后使用find_package寻找wfassoc即可。至于去哪里找这个库,我会安排其他人来做。 - 对于Qt和toml11我会安排其他人来做,你只需要用find_package来找他们就行,不需要操心能不能找到。 - 如果你对某项需求有疑问,请问我,而不是进行猜测。 ### 总结代码结构示意 (伪代码): ```cpp QDialog *dialog = new QDialog(); dialog->setWindowTitle("选项"); QVBoxLayout *mainLayout = new QVBoxLayout(dialog); // 1. Tab Widget QTabWidget *tabWidget = new QTabWidget(); tabWidget->addTab(new QWidget(), "系统"); tabWidget->addTab(new QWidget(), "7-Zip"); // ... 其他 tabs // 2. System Tab Content QWidget *systemTab = tabWidget->widget(0); QVBoxLayout *systemLayout = new QVBoxLayout(systemTab); // Label QLabel *label = new QLabel("使用 7-Zip 关联的文件类型:"); systemLayout->addWidget(label); // Buttons (+) QHBoxLayout *btnLayout = new QHBoxLayout(); QPushButton *btnPlus1 = new QPushButton("+"); QPushButton *btnPlus2 = new QPushButton("+"); btnLayout->addWidget(btnPlus1); btnLayout->addWidget(btnPlus2); systemLayout->addLayout(btnLayout); // List (TreeWidget) QTreeWidget *treeWidget = new QTreeWidget(); treeWidget->setColumnCount(3); treeWidget->setHeaderLabels(QStringList() << "类型" << "yyc12345" << "所有用户"); // 添加 items... systemLayout->addWidget(treeWidget); // 3. Bottom Buttons QHBoxLayout *bottomLayout = new QHBoxLayout(); bottomLayout->addStretch(); // 推挤按钮到右边 QPushButton *btnOK = new QPushButton("确定"); QPushButton *btnCancel = new QPushButton("取消"); QPushButton *btnApply = new QPushButton("应用(A)"); btnApply->setEnabled(false); // 禁用 QPushButton *btnHelp = new QPushButton("帮助"); bottomLayout->addWidget(btnOK); bottomLayout->addWidget(btnCancel); bottomLayout->addWidget(btnApply); bottomLayout->addWidget(btnHelp); mainLayout->addWidget(tabWidget); mainLayout->addLayout(bottomLayout); ``` 这是一个标准的 Windows 风格属性对话框,可以通过以下 Qt Widgets 结构来描述: ### 1. 主窗口容器 * 类: `QDialog`。 * 标题: "系统属性"。 * 布局: 垂直布局 (`QVBoxLayout`)。 ### 2. 顶部选项卡 (Tabs) * 组件: `QTabWidget`。 * 标签页: 包含 "计算机名", "硬件", "高级", "系统保护", "远程"。 * 当前选中: "硬件" 标签页。 ### 3. "硬件" 选项卡内容 该选项卡内部使用垂直布局 (`QVBoxLayout`),包含两个主要的分组区域(视觉上类似 `QGroupBox` 或带有边框的 `QFrame`): #### 区域 A: 设备管理器 (上半部分) * 容器: 一个带有边框的容器。 * 布局: 水平布局 (`QHBoxLayout`)。 * 左侧: 一个 `QLabel` 显示电脑图标。 * 中间: 一个 `QLabel` 显示说明文本:"设备管理器列出所有安装在计算机上的硬件设备。请使用设备管理器来更改设备的属性。" (文本需要设置自动换行 `setWordWrap(true)`)。 * 右侧/底部: 一个 `QPushButton`,文本为 "设备管理器(D)"。 #### 区域 B: 设备安装设置 (下半部分) * 容器: 一个带有边框的容器。 * 布局: 垂直布局 (`QVBoxLayout`)。 * 顶部行: 水平布局 (`QHBoxLayout`)。 * 左侧: 一个 `QLabel` 显示列表/勾选图标。 * 右侧: 一个 `QLabel` 显示说明文本:"选择 Windows 是否下载制造商提供的可用于你的设备的应用和自定义图标。" (文本需要设置自动换行)。 * 底部: 一个 `QPushButton`,文本为 "设备安装设置(S)",靠右对齐。 ### 4. 底部按钮栏 * 布局: 水平布局 (`QHBoxLayout`),右对齐 (通常通过 `addStretch()` 实现)。 * 组件: 三个 `QPushButton`。 * "确定" * "取消" * "应用(A)" (注意:截图中该按钮呈灰色,代码中需设置 `setEnabled(false)`)。 你制定的计划有一些问题,请按照下述标出的问题一一修正: - 编写的代码和说明文件需要使用英文注释。 - 是manifest而非manifesto,表示清单文件,请修正这个拼写错误。 - 我看到你在mainwindow篇章中编写了大量的C++代码,这没有必要。你是计划者而非执行者。你需要把需要在这个头文件中实现什么?该怎么做?需要使用哪些wfassoc函数,这些函数该怎么调用?在哪里查看他们怎么调用?详细的告诉将要执行这些任务的执行者,而不是直接为他们编写好代码。你在manifest部分的任务规划就非常符合这种范式。