Skillversitas

Resource Files (qrc)

The Qt resource system bundles the app's assets - the icons, the images, the style sheets, the data files - into a single binary that the app reads through the virtual :/ path, so the files travel with the binary and are not the loose files on disk beside it. The .qrc file is the XML manifest that lists the assets and their virtual paths, the pyrcc (the pyrcc5 for the PyQt5 line) compiles the .qrc into the Python module (the resources_rc), and the app registers it (the import) so the :/path/to/asset resolves. The value is the distribution: the frozen app (the PyInstaller chapter) carries the resources inside the binary, and the :/ path is the same on the dev machine and the target. This chapter covers the .qrc structure (the prefix, the file entries), the pyrcc compilation, the :/ path usage (the icon, the image, the style sheet), and the resource workflow (the asset added, the recompile, the path).

The .qrc: The Resource Manifest

<!-- the resources.qrc - the XML manifest: -->
<RCC>
  <qresource prefix="/icons">
    <file alias="app.png">assets/app.png</file>
    <file alias="save.png">assets/save.png</file>
  </qresource>
  <qresource prefix="/style">
    <file alias="app.qss">assets/app.qss</file>
  </qresource>
</RCC>

<!-- the structure: the RCC root, the qresource per
     prefix (the virtual directory), the file entries
     (the source path on disk, the alias the virtual
     name) -->
<!-- the VIRTUAL path: the prefix + the alias:
     /icons/app.png  ->  the asset is read as
     ":/icons/app.png" (the :/ is the resource root)
     the alias is the virtual filename (the source
     path is the disk's, the alias is the app's) -->

The .qrc is the XML manifest: the RCC root, the qresource elements per prefix (the virtual directory - the /icons, the /style), and the file entries (the source path on disk, the alias the virtual name). The virtual path is the prefix plus the alias: the /icons prefix with the app.png alias is read as the :/icons/app.png - the :/ is the resource root, the virtual filesystem the resources live in. The alias is the virtual filename (the source path is the disk's, the alias is what the app references), and the prefix is the virtual directory (the grouping the app's paths use). The manifest is the declarative list of the assets the app bundles, and the pyrcc (the next section) compiles it into the binary the app registers. The structure is the one that makes the :/ path work: the manifest declares the asset and its virtual path, and the compiled resource is the asset at that path.

The pyrcc: Compiling the Resource

# the pyrcc5 (the PyQt5 line; the pyrcc6 for the PyQt6):
pyrcc5 resources.qrc -o resources_rc.py
# the output: the resources_rc.py (the GENERATED, the
# compiled binary of the assets, the Python module)
# the registration: the import of the generated module
# (the import compiles the resource into the app's
# resource system, the :/ paths now resolve)
import resources_rc   # the side effect: the resource
                     # registered (the import IS the
                     # registration)

# the usage: the :/ path is the QFile / the QIcon / the
# QPixmap / the style sheet's source
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtWidgets import QApplication
import sys

app = QApplication(sys.argv)
# the icon: the :/ path (the bundled, the travels with
# the app)
app.setWindowIcon(QIcon(":/icons/app.png"))

# the image: the QPixmap from the :/ path
pixmap = QPixmap(":/icons/save.png")

# the style sheet: the read of the :/ file (the QFile)
from PyQt5.QtCore import QFile, QTextStream
f = QFile(":/style/app.qss")
if f.open(QFile.ReadOnly | QFile.Text):
    stream = QTextStream(f)
    app.setStyleSheet(stream.readAll())

# the :/ path is the SAME on the dev machine and the
# frozen target (the PyInstaller chapter bundles the
# resources_rc, the path resolves identically) - the
# resource is the asset + the virtual path, and the
# :/ is the reference the code uses

The pyrcc5 compiles the .qrc into the Python module (the resources_rc.py - the compiled binary of the assets, the generated file), and the registration is the import of that module: the import resources_rc is the side effect that registers the resource into the app's resource system, and the :/ paths now resolve. The usage is the :/ path as the source: the QIcon(":/icons/app.png") for the icon, the QPixmap(":/icons/save.png") for the image, the QFile(":/style/app.qss") read for the style sheet (the QTextStream the text). The :/ path is the same on the dev machine and the frozen target (the PyInstaller chapter bundles the resources_rc, and the path resolves identically) - the resource is the asset plus the virtual path, and the :/ is the reference the code uses. The workflow is the three steps: the .qrc declares the asset and its virtual path, the pyrcc compiles it, and the import registers it - the asset in the binary, the :/ path the code's, and the distribution the PyInstaller chapter's.

The Working Rules

  • The .qrc is the manifest, the pyrcc is the compile, the import is the register. The three steps: the manifest declares the asset and its virtual path (the prefix + the alias), the pyrcc compiles it to the resources_rc module, and the import resources_rc registers it (the side effect). The :/ path resolves only after the import.
  • The :/ path is the reference, not the disk path. The code uses the :/icons/app.png (the virtual), never the assets/app.png (the disk) - the virtual path is the same on the dev and the frozen target, and the disk path is the build's input, not the app's.
  • The resources_rc is generated, not hand-edited. The pyrcc regenerates it from the .qrc, and the asset change is the .qrc (the entry added) plus the recompile - the .qrc is the source, the resources_rc the output.
  • The alias is the virtual name, the prefix is the virtual directory. The alias is the filename the :/ path uses, and the prefix is the directory (the /icons, the /style) - the two are the virtual path the app's code references, and the source path is the disk's (the build's).
  • The resource is the distribution unit. The PyInstaller chapter bundles the resources_rc into the frozen app, and the :/ path resolves inside the binary - the asset travels with the app, not beside it on disk, and the path is stable across the deployment.

Summary

The Qt resource system bundles the app's assets (the icons, the images, the style sheets, the data) into a single binary read through the virtual :/ path. The .qrc is the XML manifest: the RCC root, the qresource per prefix (the virtual directory), and the file entries (the source path, the alias the virtual name) - the virtual path is the prefix plus the alias (the :/icons/app.png). The pyrcc5 (the pyrcc6 for the PyQt6 line) compiles the .qrc into the resources_rc module, and the import resources_rc is the registration (the side effect that makes the :/ paths resolve). The usage is the :/ path as the source: the QIcon, the QPixmap, the QFile read for the style sheet - the same path on the dev machine and the frozen target. The resources_rc is generated (the pyrcc regenerates it), the .qrc is the versionable source, and the PyInstaller chapter bundles the module into the app - the asset in the binary, the :/ path the code's, and the distribution the resource system makes stable.