Qt 资源体系(qrc rcc)

Qt 资源系统是一种与平台无关的机制,用于在应用程序的可执行文件中存储二进制文件。如果您的应用程序始终需要一组特定的文件(图标,翻译文件等),并且您不想冒丢失文件的风险,这将很有用。

资源系统基于 qmake, rcc(Qt的资源编译器)和 QFile 之间的紧密合作。

Resource Collection Files (.qrc)

与应用程序关联的资源以 .qrc 文件指定,.qrc 文件是一种基于 XML 的文件格式,该文件格式列出了磁盘上的文件,并可以选择为它们分配一个资源名称,应用程序必须使用该资源名称来访问该资源。

这是一个示例 .qrc 文件:

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
    <file>images/copy.png</file>
    <file>images/cut.png</file>
    <file>images/new.png</file>
    <file>images/open.png</file>
    <file>images/paste.png</file>
    <file>images/save.png</file>
</qresource>
</RCC>

.qrc文件中列出的资源文件是属于应用程序源树的一部分的文件。指定的路径是相对于包含.qrc文件的目录的。请注意,列出的资源文件必须与.qrc文件位于同一目录或其子目录之一。

资源数据既可以编译为二进制文件,从而可以在应用程序代码中立即访问,也可以创建二进制资源,并在以后的某个时间在应用程序代码中向资源系统注册。

默认情况下,资源可以在应用程序中以与源树中相同的文件名(带有 :/ 前缀)或具有 qrc 方案的URL进行访问。

例如,文件路径 :/images/cut.png 或 URL qrc:///images/cut.png 可以访问 cut.png 文件,该文件在应用程序源代码树中的位置为 images/cut.png。 可以使用文件标签的别名属性来更改它:

<file alias="cut-img.png">images/cut.png</file>

然后,可以从应用程序中以 :/cut-img.png 格式访问该文件。也可以使用 qresource 标记的 prefix 属性为 .qrc 文件中的所有文件指定路径前缀:

<qresource prefix="/myresources">
    <file alias="cut-img.png">images/cut.png</file>
</qresource>

在这种情况下,可以通过 :/myresources/cut-img.png 访问该文件。

一些资源需要根据用户的语言环境进行更改,例如翻译文件或图标。这是通过将 lang 属性添加到 qresource 标记,并指定合适的语言环境字符串来完成的。 例如:

<qresource>
    <file>cut.jpg</file>
</qresource>
<qresource lang="fr">
    <file alias="cut.jpg">cut_fr.jpg</file>
</qresource>

如果用户的语言环境为法语(即 QLocale::system().name() 返回 "fr_FR"),则 :/cut.jpg 成为对 cut_fr.jpg 图像的引用。对于其他语言环境,使用 cut.jpg。

有关用于语言环境字符串的格式的说明,请参见QLocale文档。

有关选择操作系统特定的功能和其他功能的信息,请参见QFileSelector,以了解选择特定于语言环境的资源的其他机制。

External Binary Resources

对于要创建的外部二进制资源,必须通过将 -binary 开关传递给 rcc 来创建资源数据(通常使用 .rcc 扩展名)。创建二进制资源后,您可以使用 QResource API 注册该资源。

例如,可以通过以下方式来编译.qrc文件中指定的一组资源数据:

rcc -binary myresource.qrc -o myresource.rcc

在应用程序中,该资源将使用以下代码进行注册:

QResource::registerResource("/path/to/myresource.rcc");

Compiled-In Resources

为了将资源编译成二进制文件,必须在应用程序的 .pro 文件中提及 .qrc 文件,以便 qmake 知道。 例如:

RESOURCES  = application.qrc

qmake 将生成 make 规则以生成一个名为 qrc_application.cpp 的文件,该文件链接到应用程序中。该文件包含图像的所有数据和其他资源,它们是压缩二进制数据的静态 C++ 数组。每当.qrc文件更改或它引用的文件之一更改时,都会自动重新生成qrc_application.cpp文件。如果不使用.pro文件,则可以手动调用 rcc 或向构建系统添加构建规则。

当前,Qt 始终将数据直接存储在可执行文件中,即使在 Windows,macOS 和 iOS 上,操作系统也提供对资源的本机支持。这可能会在将来的 Qt 版本中更改。

Compression

rcc 尝试压缩内容以优化最终二进制文件中的磁盘空间使用率。默认情况下,它将执行启发式检查以确定压缩是否值得,并且如果压缩不充分,将存储未压缩的内容。要控制阈值,可以使用-threshold选项,该选项告诉 rcc 以压缩格式存储文件时必须获得的原始文件大小的百分比。

rcc -threshold 25 myresources.qrc

默认值为“ 70”,表示压缩文件必须比原始文件小 70%(不超过原始文件大小的30%)。

如果需要,可以关闭压缩。 如果您的资源已经包含压缩格式(例如 .png文件),并且您不想在构建时招致CPU 开销以确认无法压缩,则这将很有用。另一个原因是,如果磁盘使用率不是问题,并且应用程序希望在运行时将内容保留为干净的内存页。 您可以通过提供 -no-compress 命令行参数来实现。

rcc -no-compress myresources.qrc

rcc 还使您可以控制压缩级别和压缩算法,例如:

rcc -compress 2 -compress-algo zlib myresources.qrc

还可以将 threshold, compress, 和 compress-algo 用作 .qrcfile 标记中的属性。

<qresource>
    <file compress="1" compress-algo="zstd">data.txt</file>
</qresource>

Zstandardzlib的支持是可选的。如果在编译时未检测到给定的库,则尝试对该库传递-compress-algo将会导致错误。如果启用了默认压缩算法,则为zstd;如果未启用,则为zlib。

Using Resources in the Application

在应用程序中,可以在大多数地方使用资源路径,而不是普通的文件系统路径。 特别是,您可以将资源路径而不是文件名传递给 QIcon, QImage, 或者 QPixmap 构造函数:

cutAct = new QAction(QIcon(":/images/cut.png"), tr("Cu&t"), this);

有关使用 Qt 资源系统存储其图标的实际应用程序,请参见Application示例。

在内存中,资源由资源对象树表示。该树在启动时自动构建,并由QFile用于解析资源路径。您可以使用以 ":/" 初始化的QDir从根目录浏览资源树。

Qt的资源支持搜索路径列表的概念。然后,如果您使用 : 而不是 :/ 作为前缀引用资源,则将使用搜索路径列表查找该资源。启动时搜索路径列表为空; 调用QDir::addSearchPath()添加路径。

Using Resources in a Library

如果库中有资源,则需要通过使用.qrc文件的基本名称调用Q_INIT_RESOURCE()来强制初始化资源。例如:

这样可以确保在静态链接的情况下将资源链接到最终的应用程序二进制文件中。您应该将初始化代码放在库中使用资源的位置附近,以便库客户端仅在使用依赖于资源的库功能时才链接资源。

注意:由于rcc生成的资源初始化程序是在全局名称空间中声明的,因此您对Q_INIT_RESOURCE()的调用也需要在任何名称空间之外进行。

如果库包含的资源不是内部使用的,而是暴露给库的客户端的,则初始化需要在应用程序代码中进行。例如:

与以前一样,这可以确保在静态链接的情况下将资源链接到最终的应用程序二进制文件中,但在动态链接的情况下(例如插件)也可以触发库的加载。

同样,如果必须显式卸载一组资源(因为正在卸载插件或资源不再有效),则可以通过使用与上述相同的基本名称调用Q_CLEANUP_RESOURCE()来强制删除资源。

注意:当资源作为应用程序的一部分构建时,不需要使用Q_INIT_RESOURCE() 和 Q_CLEANUP_RESOURCE()。


pyside2-rcc

首先,有一个名为 icons.qrc.qrc 文件:

</ui>
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
    <file>icons/play.png</file>
    <file>icons/pause.png</file>
    <file>icons/stop.png</file>
    <file>icons/previous.png</file>
    <file>icons/forward.png</file>
</qresource>
</RCC>

将其转换为 .py 文件:

pyrcc5 icons.qrc -o rc_icons.py # pyside2-rcc icons.qrc -o rc_icons.py

-o选项使您可以指定输出文件名,在这种情况下为 rc_icons.py

要使用生成的文件,请在主 Python 文件顶部添加以下导入:

import rc_icons

Changes in the code

修改现有示例时,需要修改以下几行:

from PySide2.QtGui import QIcon, QKeySequence
playIcon = self.style().standardIcon(QStyle.SP_MediaPlay)
previousIcon = self.style().standardIcon(QStyle.SP_MediaSkipBackward)
pauseIcon = self.style().standardIcon(QStyle.SP_MediaPause)
nextIcon = self.style().standardIcon(QStyle.SP_MediaSkipForward)
stopIcon = self.style().standardIcon(QStyle.SP_MediaStop)

并将其替换为以下内容:

from PySide2.QtGui import QIcon, QKeySequence, QPixmap
playIcon = QIcon(QPixmap(":/icons/play.png"))
previousIcon = QIcon(QPixmap(":/icons/previous.png"))
pauseIcon = QIcon(QPixmap(":/icons/pause.png"))
nextIcon = QIcon(QPixmap(":/icons/forward.png"))
stopIcon = QIcon(QPixmap(":/icons/stop.png"))

这样可以确保使用新图标代替应用程序主题提供的默认图标。请注意,这些行不是连续的,而是在文件的不同部分中。

在所有导入之后,添加以下内容:

import rc_icons

现在,您的类的构造函数应如下所示:

def __init__(self):
    super(MainWindow, self).__init__()

    self.playlist = QMediaPlaylist()
    self.player = QMediaPlayer()

    toolBar = QToolBar()
    self.addToolBar(toolBar)

    fileMenu = self.menuBar().addMenu("&File")
    openAction = QAction(QIcon.fromTheme("document-open"),
                         "&Open...", self, shortcut=QKeySequence.Open,
                         triggered=self.open)
    fileMenu.addAction(openAction)
    exitAction = QAction(QIcon.fromTheme("application-exit"), "E&xit",
                         self, shortcut="Ctrl+Q", triggered=self.close)
    fileMenu.addAction(exitAction)

    playMenu = self.menuBar().addMenu("&Play")
    playIcon = QIcon(QPixmap(":/icons/play.png"))
    self.playAction = toolBar.addAction(playIcon, "Play")
    self.playAction.triggered.connect(self.player.play)
    playMenu.addAction(self.playAction)

    previousIcon = QIcon(QPixmap(":/icons/previous.png"))
    self.previousAction = toolBar.addAction(previousIcon, "Previous")
    self.previousAction.triggered.connect(self.previousClicked)
    playMenu.addAction(self.previousAction)

    pauseIcon = QIcon(QPixmap(":/icons/pause.png"))
    self.pauseAction = toolBar.addAction(pauseIcon, "Pause")
    self.pauseAction.triggered.connect(self.player.pause)
    playMenu.addAction(self.pauseAction)

    nextIcon = QIcon(QPixmap(":/icons/forward.png"))
    self.nextAction = toolBar.addAction(nextIcon, "Next")
    self.nextAction.triggered.connect(self.playlist.next)
    playMenu.addAction(self.nextAction)

    stopIcon = QIcon(QPixmap(":/icons/stop.png"))
    self.stopAction = toolBar.addAction(stopIcon, "Stop")
    self.stopAction.triggered.connect(self.player.stop)
    playMenu.addAction(self.stopAction)

    # many lines were omitted
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,561评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,218评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,162评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,470评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,550评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,806评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,951评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,712评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,166评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,510评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,643评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,306评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,930评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,745评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,983评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,351评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,509评论 2 348