Qt 07 RCC 资源系统 学习笔记
本文介绍Qt RCC资源系统:用qt_add_resources注册文件,rcc编译期将其编入可执行体,运行时经QFile以:/虚拟路径访问。需注意加载格式须匹配实际文件。
Qt 07 RCC 资源系统 学习笔记
本章重要 API 函数
| API / 命令 | 功能 | 参数说明 | 来源 |
|---|---|---|---|
.qrc 文件 / qt_add_resources | 把图片等文件编译进可执行体 | PREFIX 设虚拟根路径;FILES 列源文件(相对 CMakeLists) | Qt RCC |
:/images/xyz/emoji.png | 以资源协议访问编译进 exe 的文件 | : 表资源 scheme;/images 是 PREFIX;后续为文件相对路径 | Qt 运行时 |
QFile(":/images/...") | 像读文件一样读资源 | 以 :/ 开头的路径,Qt 自动路由到资源系统 | <QFile> |
QPixmap::loadFromData(QByteArray, "JPG") | 从字节数组加载图片 | 第一参资源二进制;第二参格式提示 | <QPixmap> |
rcc(Qt 资源编译器) | 把 .qrc 编译为 qrc_*.cpp | 由 AUTORCC 或 qt_add_resources 隐式调用 | Qt 工具 |
💡 Tips:资源路径有两套写法易混——①
.qrc方式(见 02 的my_img.qrc,<qresource prefix="/img">+myabc/emoji.png,访问:/img/myabc/emoji.png);②qt_add_resources方式(本篇,PREFIX "images"+FILES xyz/emoji.png,访问:/images/xyz/emoji.png)。本篇hello.cpp里写的是file(":/images/xyz/emoji.png")——注意images对应PREFIX,xyz/emoji.png对应FILES里的相对路径。PREFIX不带前导/也行,Qt 会自动补,但访问时:/后紧接的就是 PREFIX 文本。
本章目录
点击条目可跳转到对应小节。
章节导航
- 本章重要 API 函数
- 学习前后依赖
- 1. 概述
- 2. 核心概念 / 原理
- 3. RCC 资源编译与访问机制
- 4. 核心代码解析
- 5. 运行效果 / 验证
- 容易踩坑
- 学习要点总结
- Q&A(常见问题)
- Tips(全局速记)
学习前后依赖
| 方向 | 内容 |
|---|---|
| 前置基础 | 03 CMake 构建 的 AUTORCC 概念;04 CMake+Qt6 的 qt_add_executable/qt_standard_project_setup;02 已用过 .qrc 资源(可在 .ui 里引用图片)。 |
| 本章核心 | 用 qt_add_resources 显式注册资源,理解 :/ 虚拟路径、rcc 编译流程与运行时访问。 |
| 后续承接 | 资源系统是后续所有”图片/图标/翻译文件/样式表”进包的基础;可与 05 VSCode/06 CLion 的 CMake 工程直接结合。 |
💡 Tips:为什么必须先会 03/04?因为
qt_add_resources是 Qt6 CMake 命令,作用在 03/04 建立的 CMake + Qt6 工程模型上;而AUTORCC(03 讲过)正是它背后的”自动触发 rcc”机制。本篇用显式qt_add_resources替代隐式AUTORCC,理解 03 的 AUTO 开关才能看懂二者的等价与差异。
1. 概述
程序运行时常常需要图片、图标、翻译 .qm、QSS 样式表等”静态文件”。如果靠相对路径从磁盘读取,会遇到路径不确定(工作目录变化)、文件被误删、部署麻烦等问题。Qt 的 资源系统(RCC, Qt Resource Compiler) 把这些文件在编译期直接编码进可执行文件,运行时通过 :/xxx 虚拟路径访问,就像访问普通文件一样,但永不依赖外部磁盘文件。
本仓库 qt07_tst-cmake-rcc_ 演示这种方式:CMakeLists.txt 用 qt_add_resources(... PREFIX "images" FILES xyz/emoji.png) 把 xyz/emoji.png 编进 exe;hello.cpp 用 QFile(":/images/xyz/emoji.png") 读取其二进制,再用 QPixmap::loadFromData 显示到 QLabel。
💡 Tips:本章最该记住的一句话——
rcc把文件变成了一段 C++ 字节数组常量,链接进 exe,运行时由 Qt 的资源虚拟文件系统(qrc:scheme)提供访问。一个反直觉点:QFile不仅能读真实磁盘文件,也能读:/资源文件——Qt 在QFile内部根据路径前缀自动选择”磁盘后端”还是”资源后端”。所以你写QFile(":/images/xyz/emoji.png")和写QFile("C:/a.png")用的是同一个类,只是数据来源不同。
2. 核心概念 / 原理
rcc 做了什么:rcc 读取 .qrc(XML,描述资源树)或 CMake 提供的 PREFIX+FILES 信息,把每个文件转换为一个压缩/原始字节数组,生成 qrc_<name>.cpp。该 cpp 里有一个静态初始化的资源树结构,注册到 Qt 的全局资源系统。链接后,这些字节就常驻 exe。
虚拟路径(:/):资源在 exe 内形成一个虚拟目录树,根用 : 表示(类似 http:// 的 scheme)。PREFIX "images" 设定第一级目录为 images,于是 FILES xyz/emoji.png 的访问路径是 :/images/xyz/emoji.png。注意 PREFIX 决定 :/ 后的第一段,而 FILES 的相对路径决定后续段。
访问后端路由:QFile/QPixmap 等以 : 开头的路径会被 Qt 资源系统拦截。若路径能以 :/ 命中已注册资源,就读内存里的字节数组;否则尝试磁盘。这让你无需关心资源是”编进 exe”还是”散在磁盘”——代码写法一致(这也是为何 02 的 .ui 里 pixmap resource="my_img.qrc" 能无缝引用资源)。
💡 Tips:原理上最易误解的是”
qt_add_resources和AUTORCC什么关系”。AUTORCC是”自动发现.qrc文件并调用 rcc”的开关;qt_add_resources是显式、不依赖.qrc文件地声明资源(直接在 CMake 里给PREFIX/FILES)。二者最终都调用rcc生成qrc_*.cpp,效果等价。显式方式的优势:资源清单写在 CMake 里、可加条件、可复用,不必为每个资源维护一个.qrc文件。
3. RCC 资源编译与访问机制
💡 Tips:流程里最关键的箭头是
F -->|":/ 前缀命中"| G——它表达”以:开头的路径被资源系统拦截并路由到内存字节数组”。另一个关键点是B --> C:qt_add_resources在 CMake 配置期就决定调用rcc(等价于 03 的AUTORCC对.qrc的处理)。务必保证PREFIX与FILES拼接出的虚拟路径,和代码里QFile(":/...")写的路径逐字符一致,否则运行时open()失败、走到IMAGE LOAD FAILED分支。
4. 核心代码解析
qt07_tst-cmake-rcc_/CMakeLists.txt 资源部分:
qt_add_executable(qt07_tst-cmake-rcc_ hello.cpp)target_link_libraries(qt07_tst-cmake-rcc_ PRIVATE Qt6::Core Qt6::Widgets)
qt_add_resources(qt07_tst-cmake-rcc_ imageresources # ① 资源目标名 imageresources PREFIX "images" # ② 虚拟根目录 /images FILES xyz/emoji.png # ③ 源文件,相对 CMakeLists 目录)# ④ 末尾仍有与 05 相同的 POST_BUILD DLL 拷贝(略)qt07_tst-cmake-rcc_/hello.cpp:
#include <QApplication>#include <QFile>#include <QLabel>#include <QPixmap>
int main(int argc, char *argv[]) { QApplication app(argc, argv);
QLabel label; QFile file(":/images/xyz/emoji.png"); // ⑤ 以资源协议打开
if (!file.open(QIODevice::ReadOnly)) { // ⑥ 资源不存在则失败分支 label.setText("RESOURCE OPEN FAILED"); label.resize(260, 80); } else { QPixmap pixmap; const QByteArray imageData = file.readAll(); // ⑦ 读全部字节 if (!pixmap.loadFromData(imageData, "JPG")) { // ⑧ 按 JPG 解码 label.setText("IMAGE LOAD FAILED"); label.resize(240, 80); } else { label.setPixmap(pixmap); label.adjustSize(); } }
label.show(); return app.exec();}逐段讲解:
- ①
qt_add_resources(... imageresources ...):imageresources是该资源目标的名字(可任意),会被加进目标的源依赖,CMake 据此调用rcc生成qrc_imageresources.cpp并链接。 - ②③
PREFIX "images"+FILES xyz/emoji.png:拼出虚拟路径:/images/xyz/emoji.png。注意FILES路径相对 CMakeLists.txt 所在目录(即xyz/emoji.png在源码根下)。 - ⑤
QFile(":/images/xyz/emoji.png"):QFile用:/前缀触发资源后端。这里有个潜在坑:资源图片实际是emoji.png(PNG 格式),但 ⑧ 里loadFromData(imageData, "JPG")却按 JPG 解码——若文件真是 PNG,解码可能失败走到IMAGE LOAD FAILED。这是源码里刻意保留的”教学陷阱”,提醒你格式声明必须与实际文件匹配(见踩坑)。 - ⑥
file.open失败分支:若PREFIX/FILES拼错导致路径不对,open()返回 false,显示RESOURCE OPEN FAILED——这是验证”资源是否真编进 exe”的最直接信号。
💡 Tips:这段代码里藏着的细节——
QFile配合:/既能读资源也能读磁盘,所以open()失败不一定是资源问题,也可能是路径拼错;而loadFromData(..., "JPG")的第二个参数强制指定解码格式,与文件真实格式不符就会失败。正确的健壮写法是用pixmap.load(&file)让 Qt 自动探测格式,或保证格式字符串与实际一致(PNG 就写 “PNG”)。
5. 运行效果 / 验证
- 构建运行
qt07_tst-cmake-rcc_,应弹出一个QLabel窗口,里面显示xyz/emoji.png这张图片(前提是loadFromData的格式与实际匹配;本仓库图片实为 PNG,若按 “JPG” 解码可能走到IMAGE LOAD FAILED,这正是踩坑点)。 - 验证资源确实编进 exe:用资源编辑器或十六进制查看 exe,应能搜到
emoji.png文件名串;或直接把xyz/emoji.png从磁盘删除再运行——若仍能显示图片,证明图片来自 exe 内嵌资源而非磁盘读取(这是 RCC 最核心的价值验证)。 - 验证路径正确性:故意把
hello.cpp里路径改成:/images/xyz/wrong.png,应显示RESOURCE OPEN FAILED,说明open()依赖精确的路径匹配。
💡 Tips:验证时容易误判”成功”的假象——图片能显示就以为资源系统生效。但如果你没删磁盘原图,也可能是
QFile回退到了磁盘读取(虽然:/前缀通常只走资源,但某些混合配置下易混淆)。最可靠的验证是删除/改名磁盘上的xyz/emoji.png后仍能显示,这才确证数据来自 exe 内嵌资源。同时注意本例loadFromData(..., "JPG")的格式陷阱可能导致即使资源编进去了也显示失败,需先把格式改成 “PNG” 或改用自动探测。
容易踩坑(注意点)
- 坑 1:虚拟路径拼错导致
open()失败。 现象:显示RESOURCE OPEN FAILED。原因:PREFIX+FILES拼出的路径与QFile(":/...")不一致(如 PREFIX 写image却访问:/images/...)。规避:对照 CMake 的PREFIX/FILES与代码路径,逐段核对。 - 坑 2:
loadFromData格式字符串与实际不符。 现象:资源读到了却显示IMAGE LOAD FAILED。原因:本例源码用"JPG"解码 PNG 文件。规避:格式串要与实际文件匹配;更稳妥用pixmap.load(&file)让 Qt 自动探测,或QPixmap::fromImage(QImage::fromData(data))。 - 坑 3:
FILES相对路径算错。 现象:rcc 报找不到文件。原因:FILES相对 CMakeLists.txt 所在目录,不是相对构建目录。规避:用相对 CMakeLists 的正确路径,或用CMAKE_CURRENT_SOURCE_DIR拼接绝对路径。 - 坑 4:以为
qt_add_resources和AUTORCC冲突。 现象:重复注册/链接错。原因:二者都会触发 rcc,对同一资源重复声明会冲突。规避:选一种方式即可;本篇用qt_add_resources(不含.qrc),就不要再AUTORCC同一个文件。 - 坑 5:忘记把资源目标关联到可执行目标。 现象:资源未编进 exe,
open()失败。原因:qt_add_resources(targetName resName ...)的第一个参数必须是已存在的可执行/库目标名。规避:确保qt_add_executable先定义,再qt_add_resources同一 target。 - 坑 6:大资源膨胀 exe 体积。 现象:exe 莫名变大。原因:资源(尤其图片)被编进二进制,且 rcc 默认压缩。规避:图片做尺寸/格式优化;或用
qt_add_resources的BASE/QML等选项精细控制;超大资源考虑运行时从磁盘/网络加载。
学习要点总结
核心知识点
- RCC 在编译期把文件变成字节数组编进 exe,运行时用
:/虚拟路径访问,不依赖外部磁盘文件。 qt_add_resources(target PREFIX "x" FILES ...)是 Qt6 显式注册资源的方式,等价于隐式AUTORCC+.qrc。- 虚拟路径 =
:/+PREFIX+FILES相对路径;QFile对:/前缀自动走资源后端。
关键 API
qt_add_resources:显式资源注册。QFile(":/..."):访问资源。QPixmap::loadFromData:从字节数组解码图片。rcc:资源编译器(被 CMake 隐式调用)。
下一步学习
- 回顾 02 QWidget 基础:那里用
.qrc(my_img.qrc)在.ui里引用图片,是 RCC 的另一种(.qrc)写法,可与本篇qt_add_resources对照。
💡 Tips:本篇与知识地图里”下一步”那篇(02)直接挂钩——02 的
my_img.qrc是 RCC 的”.qrc声明式”分支,本篇的qt_add_resources是”CMake 命令式”分支,二者底层都是 rcc,理解本篇再看 02 的.qrc会豁然开朗,反之亦然。
Q&A(常见问题)
Q1:qt_add_resources 和 .qrc + AUTORCC 该用哪个? A1:两者最终都调用 rcc 生成 qrc_*.cpp,效果等价。.qrc 方式(如 02)适合用 Qt Designer 可视化引用资源、资源结构清晰写在 XML 里;qt_add_resources 方式(本篇)适合在 CMake 里集中声明、加条件逻辑、复用资源列表,且不引入额外 .qrc 文件。小型工程用 .qrc 更直观,大型/脚本化工程用 qt_add_resources 更灵活。注意别对同一资源两种方式重复声明。
Q2:为什么 QFile 能打开 :/images/xyz/emoji.png 这种”不存在于磁盘”的路径? A2:Qt 的 QFile 内部根据路径 scheme 选择后端。以 : 开头会被路由到 Qt 资源虚拟文件系统(由 rcc 生成的静态资源树支撑),从内存字节数组读取;非 : 路径才走真实文件系统。所以 QFile(":/...") 和 QFile("C:/a.png") 接口一致、数据来源不同。这也是 QPixmap、QIcon 能直接吃 :/ 路径的原因。
Q3:Qt5 和 Qt6 在资源系统上有区别吗? A3:rcc 资源机制在 Qt5/Qt6 基本一致,QFile(":/...") 访问方式完全兼容。差异在 CMake 集成:Qt6 推荐 qt_add_resources(本篇);Qt5 用 QT5_ADD_RESOURCES 或 AUTORCC + .qrc(见 03 的 AUTORCC ON)。代码侧访问资源的写法跨版本不变。一个小变化:Qt6 对资源压缩/初始化略有优化,但使用者无感。
Tips(全局速记)
最容易忽视的细节
- 虚拟路径 =
:/+ PREFIX + FILES 相对路径,三段必须和QFile(":/...")逐字符吻合。 FILES相对 CMakeLists 目录,不是构建目录,写错 rcc 直接找不到源文件。qt_add_resources第一个参数必须是已定义的 target 名,顺序上qt_add_executable在前。
踩坑记录
- “图片能显示就以为资源生效”的错觉:没删磁盘原图时可能仍在读磁盘。删除原图仍能显示,才是 RCC 真正生效的铁证。
loadFromData(..., "JPG")格式陷阱:本例文件实为 PNG 却按 JPG 解码,会误报IMAGE LOAD FAILED。格式串必须与实际一致,或改用pixmap.load(&file)自动探测。
与后续章节的衔接
- 02 QWidget 基础:02 的
my_img.qrc是 RCC 的.qrc写法,与本篇qt_add_resources互为表里,建议对照阅读。 - 03/04 CMake 构建:
AUTORCC(03)是qt_add_resources的隐式版;04 的 Qt6 标准工程天然支持本篇命令。 - 05/06 IDE 配置:VSCode/CLion 的 CMake 工程直接容纳
qt_add_resources,clangd 对:/路径无特殊要求,照常补全。
设计决策思考
- 为什么要把资源编译进 exe,而不是运行时读磁盘? 资源内嵌带来”单文件分发、路径无关、不被误删/篡改”的好处,对图标、翻译、样式表这类小文件尤其合适。代价是 exe 体积增大、更新资源需重新编译。Qt 提供 rcc 正是为”自包含应用”而生;超大资源(视频、大图集)则应权衡,改用磁盘/网络加载。
- 为什么 Qt 提供
qt_add_resources和.qrc两种声明方式?.qrc是早期声明式方案,配合 Designer 生态成熟;qt_add_resources是 CMake 原生命令式方案,契合”一切配置在 CMake 里”的现代工程理念,便于条件包含、变量复用。两者并存让用户按工程规模与习惯选择,底层统一于 rcc,避免分裂。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
评论区
正在加载 GitHub 评论…