鸿蒙PC:Qt适配OpenHarmony实战【影单】:电影评分、简介和收藏状态的卡片式实现
欢迎加入鸿蒙PC开发者社区,共同打造开发者工具生态:鸿蒙PC开发者社区 :https://harmonypc.csdn.net/项目开源地址:https://atomgit.com/lqjmac/qtyd如果你正在把 Qt Quick 放到鸿蒙窗口里跑,最容易踩坑的往往不是控件,而是构建参数、入口符号和窗口刷新。影单。它的定位是电影卡片,核心功能是。影单 的工程价值不是功能复杂,而是把 Qt Qu
前言
欢迎加入鸿蒙PC开发者社区,共同打造开发者工具生态:鸿蒙PC开发者社区 :https://harmonypc.csdn.net/
项目开源地址:https://atomgit.com/lqjmac/qtyd
如果你正在把 Qt Quick 放到鸿蒙窗口里跑,最容易踩坑的往往不是控件,而是构建参数、入口符号和窗口刷新。
本文记录第 20 个 Qt 适配鸿蒙小项目:影单。
它的定位是 电影卡片,核心功能是 展示电影评分、简介和收藏列表。
电影卡片的重点是信息密度:评分、年份、类型、简介、收藏状态需要在一屏里有层次。
影单 的工程价值不是功能复杂,而是把 Qt Quick、OpenHarmony HAP、QML 资源和窗口刷新串成一条可复现路径。
提示:本文按真实工程路径和真实 Bundle Name 编写,命令可以直接对照项目目录执行。
推荐阅读顺序:
- 确认项目目录、中文展示名和 Bundle Name。
- 检查 Qt SDK 相对路径,避免构建机路径绑定。
- 运行构建、安装、启动和日志过滤命令。
本文包含的重点元素:
- 项目截图
- 配置表格
- 构建命令
- QML 片段
- 常见问题表
一、应用目标
1.1 项目解决什么问题
影单 不是为了把 电影卡片 做到复杂,而是为了验证 Qt Quick 在鸿蒙桌面窗口里的完整链路。
这个链路包含资源配置、Native CMake、QML 首屏、双入口导出、窗口自适应、HAP 构建和设备启动。
主要功能如下:
- 展示电影卡片列表
- 点击电影切换详情
- 展示评分年份类型简介
- 收藏或取消收藏
- 展示收藏数量和推荐片单
1.2 最终运行截图

图 1:影单 在 OpenHarmony 桌面环境里的运行效果。
1.3 关注点速览
| 关注点 | 为什么重要 | 在本项目中的体现 |
|---|---|---|
| 应用标识 | 避免 25 个 Demo 安装冲突 | com.nutpi.yingdan |
| QML 状态 | 决定界面是否能即时反馈 | 收藏状态写回 ListModel,favoriteCount() 按模型实时统计 |
| 构建参数 | 决定换机器后能否继续构建 | -DQT_PREFIX=../qtforharmony |
| 启动入口 | 避免白屏和符号缺失 | 同时保留 main 和 qtmain |
二、目录和包名
2.1 信息总览
| 项目 | 内容 |
|---|---|
| 应用展示名 | 影单 |
| 项目目录名 | QtMovieCardDemo |
| Bundle Name | com.nutpi.yingdan |
| CMake project | yingdan_moviecard |
| 项目类型 | 电影卡片 |
| 核心功能 | 展示电影评分、简介和收藏列表 |
这张表建议和 README 中的信息保持一致。项目多了以后,最怕的是展示名、包名和目录名互相错位。
2.2 目录结构
qt_for_harmony/
├── qtforharmony/
├── QtMovieCardDemo/
│ ├── AppScope/
│ ├── entry/
│ │ ├── build-profile.json5
│ │ └── src/main/cpp/
│ │ ├── CMakeLists.txt
│ │ ├── main.cpp
│ │ ├── main.qml
│ │ └── qml.qrc
│ └── README.md
└── qt-docs/
这里有一个朴素但重要的规则:Qt SDK 放在项目同级目录,不塞进每个 Demo 里面。
2.3 模块职责
| 模块 | 作用 | 检查点 |
|---|---|---|
| AppScope | 应用包名和展示名 | com.nutpi.yingdan 是否唯一 |
| entry/build-profile.json5 | native 构建参数 | Qt SDK 相对路径 |
| entry/src/main/cpp | C++ 入口和 QML | main.qml 是否进入 qrc |
| README.md | 项目说明 | 构建和启动命令是否完整 |
三、Qt SDK 相对路径
3.1 build-profile.json5
项目需要使用相对路径指定 Qt SDK。当前工程使用的关键片段如下:
{
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "-DQT_PREFIX=../qtforharmony",
"cppFlags": "",
"abiFilters": ["arm64-v8a"]
}
}
关键规则:项目需要
"arguments": "-DQT_PREFIX=../qtforharmony",SDK 文件请到文末保留的 SDK 仓库自取,并放到项目同级目录qtforharmony中。
3.2 CMakeLists.txt
cmake_minimum_required(VERSION 3.5.0)
project(yingdan_moviecard)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
get_filename_component(PROJECT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../../.." ABSOLUTE)
if (NOT IS_ABSOLUTE "${QT_PREFIX}")
get_filename_component(QT_PREFIX "${PROJECT_ROOT}/${QT_PREFIX}" ABSOLUTE)
endif()
list(PREPEND CMAKE_PREFIX_PATH ${QT_PREFIX})
find_package(Qt5 REQUIRED COMPONENTS Core Gui Qml Quick QuickControls2)
add_library(entry SHARED main.cpp qml.qrc)
这段配置先把相对的 QT_PREFIX 转成绝对路径,再交给 CMake 查找 Qt。
3.3 qml.qrc
<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>
把 QML 打进 Qt 资源系统后,运行时可以统一通过 qrc:/main.qml 加载。
四、QML 首屏组织
4.1 首屏布局
电影列表和详情卡片并排,评分条和收藏统计放在详情区域。
这种布局不是为了炫技,而是为了让 Demo 的功能一眼就能被看懂。
4.2 根节点尺寸策略
Rectangle {
id: root
width: 960
height: 1080
color: "#F5F6FA"
property real margin: Math.max(20, Math.min(48, width * 0.042))
property real gap: Math.max(12, Math.min(24, width * 0.022))
property real titleSize: Math.max(34, Math.min(58, width * 0.054))
}
根节点给出默认尺寸,真正运行时由 QQuickView::SizeRootObjectToView 接管。
4.3 本项目的数据模型
ListModel {
id: demoModel
ListElement { name: "示例项一"; state: "ready" }
ListElement { name: "示例项二"; state: "active" }
ListElement { name: "示例项三"; state: "done" }
}
实际工程中,影单 使用的是 movieModel。这些数据都在 QML 内部,适合单机演示。
五、交互逻辑拆解
5.1 函数职责表
| 函数 | 职责 |
|---|---|
currentMovie() |
切换当前展示内容 |
setMovie(indexValue) |
切换当前展示内容 |
toggleFavorite() |
处理用户操作 |
favoriteCount() |
计算界面统计值 |
scoreWidth(score) |
计算界面统计值 |
这些函数没有故意抽得很复杂。Demo 项目最重要的是让读者能从 QML 文件里直接看懂状态从哪里来、又流向哪里。
5.2 典型交互片段
MouseArea {
anchors.fill: parent
onClicked: {
// 点击后修改模型状态,界面绑定会自动刷新
demoModel.setProperty(index, "state", "done")
}
}
点击事件只负责改变状态,展示层通过绑定更新,这比手动到处刷新文本更稳。
5.3 业务函数示意
function demoFlow(row) {
var current = row
var before = demoModel.count
demoModel.setProperty(row, "state", "done")
return before
}
这段不是要照搬,而是说明当前项目的函数组织方式:
- 先从模型拿当前数据
- 再执行用户动作
- 最后让绑定表达式刷新界面
六、C++ 入口保持稳定
6.1 保留双入口
extern "C" void qtmain()
{
static ResponsiveQuickView *view = nullptr;
if (view != nullptr) {
return;
}
configureSurfaceFormat();
view = new ResponsiveQuickView();
loadQml(view);
}
int main(int argc, char *argv[])
{
configureSurfaceFormat();
QGuiApplication app(argc, argv);
ResponsiveQuickView view;
if (!loadQml(&view)) {
return -1;
}
return app.exec();
}
之前遇到过只导出 qtmain 时运行时报 Symbol not found: main 的情况,所以这一批 Qt Demo 都统一保留两个入口。
6.2 标题和 QML 加载
bool loadQml(ResponsiveQuickView *view)
{
view->setTitle(QStringLiteral("影单"));
view->setSource(QUrl(QStringLiteral("qrc:/main.qml")));
if (view->status() == QQuickView::Error) {
qWarning() << "Failed to load qrc:/main.qml";
return false;
}
view->showResponsive();
return true;
}
这里标题要和应用展示名保持一致。运行时如果日志出现 QML 加载失败,优先检查 qml.qrc。
七、命令行跑通
7.1 构建 HAP
cd QtMovieCardDemo
/Users/luqingjiedemac/ohos/command-line-tools/bin/hvigorw assembleHap --stacktrace
构建完成后,HAP 默认输出在下面这个路径:
entry/build/default/outputs/default/entry-default-unsigned.hap
7.2 安装和启动
hdc install -r entry/build/default/outputs/default/entry-default-unsigned.hap
hdc shell aa start -a EntryAbility -b com.nutpi.yingdan -m entry
启动命令里的 Bundle Name 必须和 AppScope/app.json5 一致。
7.3 构建失败先看哪里
QT_PREFIX是否指向同级qtforharmony。CMakeLists.txt的 project 名称是否已经替换。main.qml是否存在于qml.qrc中。
八、窗口缩放验证
8.1 过滤关键日志
hdc shell hilog -x -z 500 | rg -n "QtForOpenHarmony|QPAForOpenHarmony|yingdan|Failed|failed|Error|error|qrc|main function|Symbol not found|QML|ReferenceError|TypeError"
我重点看这些信号:
- 是否出现
Symbol not found: main - 是否出现
Failed to load qrc:/main.qml - 是否出现 QML 的
ReferenceError或TypeError - 是否能看到应用进程还在运行
8.2 截图命令
hdc shell snapshot_display -f /data/local/tmp/yingdan_screen.jpeg
hdc file recv /data/local/tmp/yingdan_screen.jpeg ./qt-docs/assets/yingdan-screen.jpeg
截图不是装饰,它是确认首屏真的渲染出来的证据。
8.3 当前项目验证点
- 点击电影后详情同步
- 收藏数量变化
- 评分条长度与分数匹配
经验:这类小项目最适合把功能做窄,把构建、启动、截图、日志验证做完整。
九、问题表
9.1 常见问题表
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| 白屏 | QML 没加载成功或窗口未刷新 | 检查 qrc:/main.qml 和日志 |
| 找不到 main | 只保留了 qtmain |
同时导出 main 和 qtmain |
| 构建找不到 Qt | QT_PREFIX 路径错误 |
使用 -DQT_PREFIX=../qtforharmony |
| 启动失败 | Bundle Name 写错 | 对照 com.nutpi.yingdan |
| 窗口缩放不刷新 | 根对象没有跟随窗口尺寸 | 使用响应式 QQuickView 刷新策略 |
9.2 排查顺序
- 先看 HAP 是否重新构建。
- 再看安装的包名是不是当前项目。
- 然后看日志里有没有 QML 或 main 符号错误。
- 最后才去调整具体控件布局。
十、下一步迭代
10.1 可以继续做的功能
- 增加搜索和筛选
- 接入海报图片
- 保存收藏列表
这些扩展不建议一口气全做。Qt 适配鸿蒙的早期样例,优先目标应该是结构稳定、运行稳定、验证路径稳定。
10.2 工程增强方向
QtObject {
id: appState
property int currentIndex: 0
property bool dirty: false
property string message: "ready"
}
当页面状态继续变多,可以把零散属性收进一个 QtObject,这样顶层不会越来越乱。
10.3 清理和重建
rm -rf entry/build entry/.cxx .hvigor
/Users/luqingjiedemac/ohos/command-line-tools/bin/hvigorw assembleHap --stacktrace
遇到缓存比较顽固的问题时,可以清掉构建产物后重建。正常开发时不需要每次都清理。
十一、相关入口
11.1 OpenHarmony 文档入口
OpenHarmony 文档中心:https://docs.openharmony.cn/
11.2 Qt for Harmony SDK 仓库
Qt for Harmony SDK 仓库:https://atomgit.com/nutpi/qtforharmony_sdk
11.3 为什么只保留三个链接
这批文章用于项目发布和读者复现。链接过多会分散注意力,所以正文只保留社区入口、OpenHarmony 文档和 Qt SDK 仓库三个入口。
总结
影单 这个 Demo 的重点是 展示电影评分、简介和收藏列表。
从工程角度看,它已经覆盖了 Qt for OpenHarmony 项目里最关键的几步:配置 Qt SDK、打包 QML、保留双入口、构建 HAP、安装启动和截图验证。
如果你也在做 Qt 适配鸿蒙,可以先用这种小项目把链路跑稳,再逐步接入更真实的数据和业务。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
更多推荐



所有评论(0)