首页
下载
文档
社区
视频
捐赠
开源项目
typephp
swoole
code-galaxy
swoole-cli
phpx
phpy
赞助商
AOT 编译器
AI 助理
商业产品
Swoole-Compiler 代码加密器
CRMEB 新零售社交电商系统
登录
注册
全部
提问
分享
讨论
建议
公告
开发框架
TypePHP
CodeGalaxy
发表新帖
用 TypePHP + Qt 开发 Windows 桌面软件:从任务板到可运行的应用
PHP 能否承担 Windows 桌面软件的主要开发工作?我们做了一个任务板来验证:它有项目管理软件常见的侧边导航、任务列表、搜索、状态统计、详情面板和编辑弹窗。任务的校验、状态流转、筛选和存储都由 PHP 完成;C++ 只负责封装 Qt Widgets 的控件与事件。 这不是一张设计稿。下面的画面来自 **Windows x64 测试机上编译并运行的程序**,使用 Qt 6.8.3、MSVC 2022 和 PHP 8.4 ZTS。应用首次启动时,由 PHP 通过 PDO SQLite 建表并写入五条示例任务。  界面取了 [Linear 看板](https://linear.app/docs/board-layout)一类项目管理软件的简洁布局思路,但使用原生 Qt Widgets 实现。左侧按状态浏览,中间搜索和选择任务,右侧查看说明并推进状态。新建、编辑、删除后,界面数据会从数据库重新读取。 ## 从点击到数据库,谁负责什么 示例位于 `compiler/examples/qt-taskboard/`: ```text qt-taskboard/ ├── main.php 程序入口与数据库路径 ├── app/TaskBoardApplication.php 事件处理、筛选、统计、状态流转 ├── app/TaskStore.php PDO SQLite、校验与增删改查 ├── php-src/taskboard.stub.php PHP 可调用的 Qt 桥接口 ├── cpp-src/taskboard.cc Qt 控件、绘制、输入与事件队列 ├── project.windows.yml Windows MSVC 构建参数 └── tests/task_store_test.php 无 Qt 依赖的数据层测试 ``` 一次“开始任务”的调用链如下: ```text Qt 按钮点击 → C++ 把 {type: "advance", id: "..."} 放入队列 → PHP 读取事件,查询 SQLite,计算下一个状态并保存 → PHP 重新查询、筛选、统计任务 → C++ 只按 PHP 给出的数据刷新控件 ``` 在 `TaskBoardApplication.php` 中,事件分派就是普通 PHP: ```php if ($type === 'advance') { $this->store->advance($id); $this->selectedId = $id; } $this->refresh(); ``` `refresh()` 遍历任务,计算全部、进行中、已完成的数量,执行状态过滤和关键词匹配,再调用 `qt_board_set_view()`。Qt 桥并不知道“完成后应回到待处理”这类业务规则,它只展示结果。原生接口通过 `taskboard.stub.php` 声明,例如 `qt_board_poll_event()`、`qt_board_set_view()`;C++ 对应实现处理 `QTableWidget`、`QDialog` 和信号连接。 ## 为什么用 PHP PDO SQLite 单个 JSON 文件足以保存小型设置,但任务板会频繁按 ID 更新、删除和查询任务。SQLite 更适合这个场景:数据仍是一个本地文件,PHP 可以用参数化 SQL 操作它,并用事务保证首次写入的示例数据完整。这里使用的是 **PHP 的 `PDO_SQLITE` 驱动**,没有使用 Qt SQL 模块,也没有把数据库逻辑搬到 C++。[PHP 手册](https://www.php.net/manual/en/ref.pdo-sqlite.php)提供了该驱动的说明。 建表和连接的关键代码在 `TaskStore.php`: ```php $this->db = new PDO('sqlite:' . $file); $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->db->exec('CREATE TABLE IF NOT EXISTS tasks ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT NOT NULL, status TEXT NOT NULL, priority TEXT NOT NULL, created_at TEXT NOT NULL )'); ``` 保存任务使用预处理语句;PHP 先检查标题、状态和优先级,再执行 `INSERT ... ON CONFLICT(id) DO UPDATE`。默认数据库位于 `%APPDATA%\TypePHP\taskboard.sqlite`,也可以用 `TYPEPHP_TASKBOARD_DATA` 指定路径。关闭再打开程序,任务会保留。 ## 在 Windows 上编译 准备 Windows x64、Visual Studio 2022 C++ 工具链、PHP 8.4 ZTS 及其 SDK、匹配的 PHPX,以及 **Qt 6.8.3 的 MSVC 2022 64-bit 套件**。Qt 可通过官方 Online Installer 安装;选择桌面版 MSVC 2022 x64,不要选 MinGW 套件。Qt 的 [Windows 平台文档](https://doc.qt.io/qt-6/windows.html)列出了支持的工具链。 `project.windows.yml` 已写入本次测试机使用的 `D:/workspace/qt/6.8.3/msvc2022_64`。其他机器只需把文件里的 Qt 根路径替换为实际安装路径。MSVC 参数中有两项不能漏: ```yaml cxx-flags: - '/Zc:__cplusplus' - '/permissive-' - '/I"D:/workspace/qt/6.8.3/msvc2022_64/include"' # 还需 QtCore、QtGui、QtWidgets 的 include 路径 ld-flags: - '/LIBPATH:"D:/workspace/qt/6.8.3/msvc2022_64/lib"' - Qt6Widgets.lib - Qt6Gui.lib - Qt6Core.lib ``` 在 **x64 Native Tools Command Prompt for VS 2022** 中切到 `compiler` 目录,按自己的路径设置环境变量并编译: ```bat set "PHP_HOME=D:\workspace\php-8.4.23" set "PHPX_HOME=D:\workspace\phpx" set "PATH=D:\workspace\qt\6.8.3\msvc2022_64\bin;%PHPX_HOME%\lib;%PHP_HOME%;%PATH%" "%PHP_HOME%\php.exe" -n bin\tpc.php examples\qt-taskboard\project.windows.yml --job 2 --no-progress ``` 这里 `-n` 仅用于**编译器进程**。运行桌面程序时需要让嵌入的 PHP 加载 PDO SQLite。可以给示例单独创建一个 `runtime.ini`,不改系统的 PHP 配置: ```ini extension_dir=D:\workspace\php-8.4.23\ext extension=php_pdo_sqlite.dll ``` 随后运行: ```bat set "PHPRC=D:\workspace\compiler\examples\qt-taskboard\runtime.ini" set "PHP_INI_SCAN_DIR=" typephp_taskboard.exe ``` 本次测试机上,MSVC 构建成功,程序创建了 `taskboard.sqlite`,并渲染出文首截图。数据层还可脱离 Qt 单独验证: ```bat "%PHP_HOME%\php.exe" -c examples\qt-taskboard\runtime.ini examples\qt-taskboard\tests\task_store_test.php ``` ## 同一套代码在 macOS 上也能运行吗? 我们在 Apple Silicon 测试机上做了完整验证:macOS arm64、PHP 8.4.20 ZTS(内置 PDO SQLite)、Xcode Clang、Homebrew `qtbase` 6.11.2。任务板编译成 **Mach-O arm64 可执行文件**,随后使用默认的 Qt Cocoa 平台插件启动;PHP 创建 SQLite 数据库,Qt 渲染出下面的界面。macOS 版本使用的仍是同一份 `main.php`、`TaskStore.php`、`TaskBoardApplication.php` 和 Qt 桥代码,只换了构建配置 `project.macos.yml`。 macOS 测试机安装 Qt Widgets 基础组件使用 `brew install qtbase`。在 Apple Silicon 的默认 Homebrew 路径下,从 `compiler` 目录编译: ```bash export PHP_HOME="$HOME/.phpbrew/php/php-8.4.20-zts" export PHPX_HOME="$HOME/workspace/phpx" "$PHP_HOME/bin/php" -n bin/tpc.php examples/qt-taskboard/project.macos.yml --job 2 --no-progress sh examples/qt-taskboard/package-macos-app.sh ``` 生成的 `examples/qt-taskboard/dist/TypePHP Taskboard.app` 可以直接在 Finder 中双击。开发时也可以用 `open "examples/qt-taskboard/dist/TypePHP Taskboard.app"` 验证。macOS 桌面程序由 `.app` 包和 `Info.plist` 交给 LaunchServices 启动,**不需要 `--no-console`**;这个参数只用于 Windows 的 GUI 子系统。独立的打包脚本调用 `macdeployqt`,收集 Qt 框架和插件,同时打入 PHP/PHPX 运行库并进行本机临时签名。Qt 的 [macOS 部署文档](https://doc.qt.io/qt-6/macos-deployment.html)说明了应用包结构与 Qt 依赖部署。 我们在测试机上通过 LaunchServices 启动了 `.app`,程序作为独立 GUI 进程持续运行,没有打开终端。PHPX 需要针对同一套 PHP 编译;这个 PHP 构建用 `php -n -m` 就能看到 `PDO` 与 `pdo_sqlite`,数据层测试返回 `task-store-ok`。Qt 官方的 [macOS 平台文档](https://doc.qt.io/qt-6/macos.html)列出了 Apple Silicon 和当前 macOS 的支持情况。向其他 Mac 分发时,还应在干净机器上验证,并完成正式签名与公证。 ## 部署时带上运行库 开发机上能启动,不等于把单个 `.exe` 复制出去就能运行。Qt 官方建议用 `windeployqt` 收集 Qt DLL 和平台插件;它不会自动收集应用的所有第三方依赖。[Qt Windows 部署文档](https://doc.qt.io/qt-6/windows-deployment.html)对此有明确说明。 ```bat D:\workspace\qt\6.8.3\msvc2022_64\bin\windeployqt.exe --release typephp_taskboard.exe ``` 还要按实际构建准备匹配的 PHP/PHPX 运行库、`php_pdo_sqlite.dll`、PHP 配置文件及其他非 Qt DLL。先保留控制台查看启动错误;确认运行无误后,可以在 TypePHP 编译命令中加入 `--no-console` 生成 GUI 子系统程序。 ## 结语:让 PHP 承担桌面应用的主要逻辑 这块任务板展示了 TypePHP + Qt 的一条完整开发路径:PHP 处理输入校验、任务状态、搜索统计和 SQLite 持久化;Qt 提供窗口、表格、对话框和原生交互;TypePHP 把两部分编译、链接成可在 Windows 运行的程序。用户点击按钮后,事件能回到 PHP,PHP 更新数据后又能驱动界面刷新。这已经覆盖了许多桌面业务工具最常见的工作流程。 这样的分工也方便扩展。比如增加截止日期、标签或多项目视图,数据结构和业务规则可以继续写在 PHP 中;界面需要新的控件时,再通过一层 C++ 接口把对应的 Qt 能力开放出来。已有 PHP 代码和测试可以继续发挥作用,桌面端则使用 Qt 的原生控件。 目前我们已在 Windows 上完成构建、运行和截图,并在 Windows、Linux 上验证了 PDO SQLite 数据层。示例封装的是任务板实际用到的 Qt 接口;文件选择、系统托盘等更多桌面能力,可以沿用同样的桥接方式逐步加入。TypePHP + Qt 适合从一个功能明确的本地工具起步,再把 PHP 熟悉的业务开发方式延伸到桌面。
发布于2周前 · 5 次浏览 · 来自
TypePHP
Rango-H
PHP 能否承担 Windows 桌面软件的主要开发工作?我们做了一个任务板来验证:它有项目管理软件常见的侧边导航、任务列表、搜索、状态统计、详情面板和编辑弹窗。任务的校验、状态流转、筛选和存储都由 PHP 完成;C++ 只负责封装 Qt Widgets 的控件与事件。 这不是一张设计稿。下面的画面来自 **Windows x64 测试机上编译并运行的程序**,使用 Qt 6.8.3、MSVC 2022 和 PHP 8.4 ZTS。应用首次启动时,由 PHP 通过 PDO SQLite 建表并写入五条示例任务。  界面取了 [Linear 看板](https://linear.app/docs/board-layout)一类项目管理软件的简洁布局思路,但使用原生 Qt Widgets 实现。左侧按状态浏览,中间搜索和选择任务,右侧查看说明并推进状态。新建、编辑、删除后,界面数据会从数据库重新读取。 ## 从点击到数据库,谁负责什么 示例位于 `compiler/examples/qt-taskboard/`: ```text qt-taskboard/ ├── main.php 程序入口与数据库路径 ├── app/TaskBoardApplication.php 事件处理、筛选、统计、状态流转 ├── app/TaskStore.php PDO SQLite、校验与增删改查 ├── php-src/taskboard.stub.php PHP 可调用的 Qt 桥接口 ├── cpp-src/taskboard.cc Qt 控件、绘制、输入与事件队列 ├── project.windows.yml Windows MSVC 构建参数 └── tests/task_store_test.php 无 Qt 依赖的数据层测试 ``` 一次“开始任务”的调用链如下: ```text Qt 按钮点击 → C++ 把 {type: "advance", id: "..."} 放入队列 → PHP 读取事件,查询 SQLite,计算下一个状态并保存 → PHP 重新查询、筛选、统计任务 → C++ 只按 PHP 给出的数据刷新控件 ``` 在 `TaskBoardApplication.php` 中,事件分派就是普通 PHP: ```php if ($type === 'advance') { $this->store->advance($id); $this->selectedId = $id; } $this->refresh(); ``` `refresh()` 遍历任务,计算全部、进行中、已完成的数量,执行状态过滤和关键词匹配,再调用 `qt_board_set_view()`。Qt 桥并不知道“完成后应回到待处理”这类业务规则,它只展示结果。原生接口通过 `taskboard.stub.php` 声明,例如 `qt_board_poll_event()`、`qt_board_set_view()`;C++ 对应实现处理 `QTableWidget`、`QDialog` 和信号连接。 ## 为什么用 PHP PDO SQLite 单个 JSON 文件足以保存小型设置,但任务板会频繁按 ID 更新、删除和查询任务。SQLite 更适合这个场景:数据仍是一个本地文件,PHP 可以用参数化 SQL 操作它,并用事务保证首次写入的示例数据完整。这里使用的是 **PHP 的 `PDO_SQLITE` 驱动**,没有使用 Qt SQL 模块,也没有把数据库逻辑搬到 C++。[PHP 手册](https://www.php.net/manual/en/ref.pdo-sqlite.php)提供了该驱动的说明。 建表和连接的关键代码在 `TaskStore.php`: ```php $this->db = new PDO('sqlite:' . $file); $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->db->exec('CREATE TABLE IF NOT EXISTS tasks ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT NOT NULL, status TEXT NOT NULL, priority TEXT NOT NULL, created_at TEXT NOT NULL )'); ``` 保存任务使用预处理语句;PHP 先检查标题、状态和优先级,再执行 `INSERT ... ON CONFLICT(id) DO UPDATE`。默认数据库位于 `%APPDATA%\TypePHP\taskboard.sqlite`,也可以用 `TYPEPHP_TASKBOARD_DATA` 指定路径。关闭再打开程序,任务会保留。 ## 在 Windows 上编译 准备 Windows x64、Visual Studio 2022 C++ 工具链、PHP 8.4 ZTS 及其 SDK、匹配的 PHPX,以及 **Qt 6.8.3 的 MSVC 2022 64-bit 套件**。Qt 可通过官方 Online Installer 安装;选择桌面版 MSVC 2022 x64,不要选 MinGW 套件。Qt 的 [Windows 平台文档](https://doc.qt.io/qt-6/windows.html)列出了支持的工具链。 `project.windows.yml` 已写入本次测试机使用的 `D:/workspace/qt/6.8.3/msvc2022_64`。其他机器只需把文件里的 Qt 根路径替换为实际安装路径。MSVC 参数中有两项不能漏: ```yaml cxx-flags: - '/Zc:__cplusplus' - '/permissive-' - '/I"D:/workspace/qt/6.8.3/msvc2022_64/include"' # 还需 QtCore、QtGui、QtWidgets 的 include 路径 ld-flags: - '/LIBPATH:"D:/workspace/qt/6.8.3/msvc2022_64/lib"' - Qt6Widgets.lib - Qt6Gui.lib - Qt6Core.lib ``` 在 **x64 Native Tools Command Prompt for VS 2022** 中切到 `compiler` 目录,按自己的路径设置环境变量并编译: ```bat set "PHP_HOME=D:\workspace\php-8.4.23" set "PHPX_HOME=D:\workspace\phpx" set "PATH=D:\workspace\qt\6.8.3\msvc2022_64\bin;%PHPX_HOME%\lib;%PHP_HOME%;%PATH%" "%PHP_HOME%\php.exe" -n bin\tpc.php examples\qt-taskboard\project.windows.yml --job 2 --no-progress ``` 这里 `-n` 仅用于**编译器进程**。运行桌面程序时需要让嵌入的 PHP 加载 PDO SQLite。可以给示例单独创建一个 `runtime.ini`,不改系统的 PHP 配置: ```ini extension_dir=D:\workspace\php-8.4.23\ext extension=php_pdo_sqlite.dll ``` 随后运行: ```bat set "PHPRC=D:\workspace\compiler\examples\qt-taskboard\runtime.ini" set "PHP_INI_SCAN_DIR=" typephp_taskboard.exe ``` 本次测试机上,MSVC 构建成功,程序创建了 `taskboard.sqlite`,并渲染出文首截图。数据层还可脱离 Qt 单独验证: ```bat "%PHP_HOME%\php.exe" -c examples\qt-taskboard\runtime.ini examples\qt-taskboard\tests\task_store_test.php ``` ## 同一套代码在 macOS 上也能运行吗? 我们在 Apple Silicon 测试机上做了完整验证:macOS arm64、PHP 8.4.20 ZTS(内置 PDO SQLite)、Xcode Clang、Homebrew `qtbase` 6.11.2。任务板编译成 **Mach-O arm64 可执行文件**,随后使用默认的 Qt Cocoa 平台插件启动;PHP 创建 SQLite 数据库,Qt 渲染出下面的界面。macOS 版本使用的仍是同一份 `main.php`、`TaskStore.php`、`TaskBoardApplication.php` 和 Qt 桥代码,只换了构建配置 `project.macos.yml`。 macOS 测试机安装 Qt Widgets 基础组件使用 `brew install qtbase`。在 Apple Silicon 的默认 Homebrew 路径下,从 `compiler` 目录编译: ```bash export PHP_HOME="$HOME/.phpbrew/php/php-8.4.20-zts" export PHPX_HOME="$HOME/workspace/phpx" "$PHP_HOME/bin/php" -n bin/tpc.php examples/qt-taskboard/project.macos.yml --job 2 --no-progress sh examples/qt-taskboard/package-macos-app.sh ``` 生成的 `examples/qt-taskboard/dist/TypePHP Taskboard.app` 可以直接在 Finder 中双击。开发时也可以用 `open "examples/qt-taskboard/dist/TypePHP Taskboard.app"` 验证。macOS 桌面程序由 `.app` 包和 `Info.plist` 交给 LaunchServices 启动,**不需要 `--no-console`**;这个参数只用于 Windows 的 GUI 子系统。独立的打包脚本调用 `macdeployqt`,收集 Qt 框架和插件,同时打入 PHP/PHPX 运行库并进行本机临时签名。Qt 的 [macOS 部署文档](https://doc.qt.io/qt-6/macos-deployment.html)说明了应用包结构与 Qt 依赖部署。 我们在测试机上通过 LaunchServices 启动了 `.app`,程序作为独立 GUI 进程持续运行,没有打开终端。PHPX 需要针对同一套 PHP 编译;这个 PHP 构建用 `php -n -m` 就能看到 `PDO` 与 `pdo_sqlite`,数据层测试返回 `task-store-ok`。Qt 官方的 [macOS 平台文档](https://doc.qt.io/qt-6/macos.html)列出了 Apple Silicon 和当前 macOS 的支持情况。向其他 Mac 分发时,还应在干净机器上验证,并完成正式签名与公证。 ## 部署时带上运行库 开发机上能启动,不等于把单个 `.exe` 复制出去就能运行。Qt 官方建议用 `windeployqt` 收集 Qt DLL 和平台插件;它不会自动收集应用的所有第三方依赖。[Qt Windows 部署文档](https://doc.qt.io/qt-6/windows-deployment.html)对此有明确说明。 ```bat D:\workspace\qt\6.8.3\msvc2022_64\bin\windeployqt.exe --release typephp_taskboard.exe ``` 还要按实际构建准备匹配的 PHP/PHPX 运行库、`php_pdo_sqlite.dll`、PHP 配置文件及其他非 Qt DLL。先保留控制台查看启动错误;确认运行无误后,可以在 TypePHP 编译命令中加入 `--no-console` 生成 GUI 子系统程序。 ## 结语:让 PHP 承担桌面应用的主要逻辑 这块任务板展示了 TypePHP + Qt 的一条完整开发路径:PHP 处理输入校验、任务状态、搜索统计和 SQLite 持久化;Qt 提供窗口、表格、对话框和原生交互;TypePHP 把两部分编译、链接成可在 Windows 运行的程序。用户点击按钮后,事件能回到 PHP,PHP 更新数据后又能驱动界面刷新。这已经覆盖了许多桌面业务工具最常见的工作流程。 这样的分工也方便扩展。比如增加截止日期、标签或多项目视图,数据结构和业务规则可以继续写在 PHP 中;界面需要新的控件时,再通过一层 C++ 接口把对应的 Qt 能力开放出来。已有 PHP 代码和测试可以继续发挥作用,桌面端则使用 Qt 的原生控件。 目前我们已在 Windows 上完成构建、运行和截图,并在 Windows、Linux 上验证了 PDO SQLite 数据层。示例封装的是任务板实际用到的 Qt 接口;文件选择、系统托盘等更多桌面能力,可以沿用同样的桥接方式逐步加入。TypePHP + Qt 适合从一个功能明确的本地工具起步,再把 PHP 熟悉的业务开发方式延伸到桌面。
赞
1
收藏
提问
分享
讨论
建议
公告
开发框架
TypePHP
CodeGalaxy
登录
后参与评论
评论
2026-09-30
dai
666
赞
0
回复