Projecte: A08.04.3_configB
Objectiu: Aprendre gestió moderna de recursos en Qt6 i persistència de dades amb Settings
Aquest projecte és una evolució del joc Pedra, Paper, Tisores bàsic que ja heu desenvolupat. Afegeix dues funcionalitats importants:
Però el més important: utilitza la gestió moderna de recursos de Qt6, sense fitxers .qrc.
.qrc (mètode Qt5)El fitxer .qrc és un fitxer XML que Qt5 utilitzava per gestionar recursos:
<!-- qml.qrc - Mètode ANTIC (Qt5) -->
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>img/rock.png</file>
<file>img/paper.png</file>
</qresource>
</RCC>
Problemes:
En Qt6, declarem els recursos directament al CMakeLists.txt:
qt_add_qml_module(rps-config
URI rpsconfig # Nom del mòdul
VERSION 1.0 # Versió
QML_FILES # Fitxers QML
main.qml
ThemeManager.qml
BotoRPS.qml
PaginaJoc.qml
ConfigPage.qml
ControlButtons.qml
VistaJugada.qml
RESOURCES # Recursos (imatges, fonts, etc.)
img/rock.png
img/paper.png
img/scissors.png
img/settings.png
img/save.png
)
Avantatges:
Quan compiles, Qt crea aquesta estructura:
build/
└── rpsconfig/ # Nom del mòdul (URI)
├── main.qml
├── ThemeManager.qml
├── BotoRPS.qml
├── img/
│ ├── rock.png
│ └── paper.png
└── qmldir # Generat automàticament
Els recursos s'encasten dins de l'executable i estan disponibles amb paths com:
qrc:/qt/qml/rpsconfig/img/rock.pngimg/rock.png ← RecomanatImage {
source: "rock.png" // Busca al sistema de fitxers
}
Problema: Funciona durant el desenvolupament però NO en l'executable distribuït.
Image {
source: "img/rock.png" // Path relatiu al mòdul
}
Avantatge: Curt, net, funciona sempre.
Image {
source: "qrc:/qt/qml/rpsconfig/img/rock.png" // Path complet
}
Avantatge: Explícit, funciona des de qualsevol lloc.
Desavantatge: Llarg i menys llegible.
| Mètode | Path al QML | Funciona en executable? | Recomanat |
|---|---|---|---|
| Sense qrc:/ | "rock.png" |
❌ NO | Mai |
| Relatiu (mòdul) | "img/rock.png" |
✅ SÍ | Sí |
| Absolut | "qrc:/qt/qml/rpsconfig/img/rock.png" |
✅ SÍ | Si cal |
CMakeLists.txt:
qt_add_qml_module(rps-config
URI rpsconfig
QML_FILES BotoRPS.qml
RESOURCES img/rock.png
)
BotoRPS.qml:
import QtQuick
Item {
property string font // Rebem el path de la imatge
Image {
source: font // "img/rock.png" (path relatiu)
anchors.centerIn: parent
fillMode: Image.PreserveAspectFit
}
}
ControlButtons.qml:
Repeater {
model: [
{tipus: "R", font: "img/rock.png"}, // Path relatiu
{tipus: "P", font: "img/paper.png"},
{tipus: "S", font: "img/scissors.png"}
]
BotoRPS {
text: modelData.tipus
font: modelData.font // Passa el path al component
}
}
Un singleton és un objecte que:
Exemple d'ús: Gestionar el tema (clar/fosc) de tota l'aplicació des d'un sol lloc.
Imagina que vols canviar el color de fons de l'aplicació:
// PaginaJoc.qml
Rectangle {
color: root.isDark ? "#1E1E1E" : "#FFFFFF" // Duplicat!
}
// ConfigPage.qml
Rectangle {
color: root.isDark ? "#1E1E1E" : "#FFFFFF" // Duplicat!
}
// BotoRPS.qml
Rectangle {
color: root.isDark ? "#2D2D2D" : "#F5F5F5" // Més duplicació!
}
Problemes:
// PaginaJoc.qml
Rectangle {
color: ThemeManager.backgroundColor // Centralitzat!
}
// ConfigPage.qml
Rectangle {
color: ThemeManager.backgroundColor // Mateix codi!
}
// Canviar el tema des de qualsevol lloc:
Button {
onClicked: ThemeManager.toggleTheme()
}
pragma SingletonThemeManager.qml:
pragma Singleton // ← IMPORTANT: Declara que és singleton
import QtQuick
QtObject {
id: themeManager
// Propietat principal
property bool darkMode: false
// Colors mode clar
property color lightBackground: "#FFFFFF"
property color lightText: "#000000"
// Colors mode fosc
property color darkBackground: "#1E1E1E"
property color darkText: "#FFFFFF"
// Colors actius (calculats segons darkMode)
property color backgroundColor: darkMode ? darkBackground : lightBackground
property color textColor: darkMode ? darkText : lightText
// Funció per canviar el tema
function toggleTheme() {
darkMode = !darkMode
}
}
qmldir:
module rpsconfig
singleton ThemeManager 1.0 ThemeManager.qml
Sintaxi:
module rpsconfig - Nom del mòdul (ha de coincidir amb URI al CMakeLists.txt)singleton - Paraula clau que indica que és un singletonThemeManager - Nom amb què s'accedeix des dels QML1.0 - VersióThemeManager.qml - Fitxer fontimport rpsconfig // Importa el mòdul
Rectangle {
color: ThemeManager.backgroundColor // Accés directe
Text {
color: ThemeManager.textColor
text: "Hola món"
}
Button {
text: "Canviar tema"
onClicked: ThemeManager.toggleTheme()
}
}
┌─────────────────┐
│ ThemeManager │ ← Una sola instància
│ (Singleton) │
└────────┬────────┘
│
┌────┴────┬────────┬────────┐
│ │ │ │
PaginaJoc ConfigPage Botons etc.
│ │ │ │
Accedeixen a la mateixa instància
Quan canvies darkMode, tots els colors s'actualitzen automàticament:
property color backgroundColor: darkMode ? darkBackground : lightBackground
// ↑ Quan darkMode canvia, aquesta expressió
// es recalcula automàticament
Això s'anomena binding en Qt:
Qt.labs.settings és un component QML que:
| Plataforma | Ubicació |
|---|---|
| Linux | ~/.config/ExempleOrg/RPSConfig.conf |
| macOS | ~/Library/Preferences/cat.exemple.RPSConfig.plist |
| Windows | Registre: HKEY_CURRENT_USER\Software\ExempleOrg\RPSConfig |
| Android | SharedPreferences intern |
main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
// IMPORTANT: Defineix organització i aplicació
QCoreApplication::setOrganizationName("ExempleOrg");
QCoreApplication::setOrganizationDomain("exemple.cat");
QCoreApplication::setApplicationName("RPSConfig");
// Sense això, Settings no sap on guardar les dades!
QQmlApplicationEngine engine;
engine.loadFromModule("rpsconfig", "Main");
return app.exec();
}
main.qml:
import QtQuick
import Qt.labs.settings 1.0 // Importa Settings
ApplicationWindow {
id: root
// Dades locals de l'aplicació
property bool soundEnabled: true
property int gamesPlayed: 0
// Settings: guarda automàticament
Settings {
// property alias NOM_SETTING: objecte.propietat
property alias darkMode: ThemeManager.darkMode
property alias sound: root.soundEnabled
property alias games: root.gamesPlayed
}
// Quan darkMode canvia → es guarda automàticament
// Quan l'app s'inicia → es carrega automàticament
}
Inici de l'aplicació:
1. Qt carrega Settings des del disc
2. Assigna valors a les propietats (darkMode, soundEnabled, etc.)
3. L'app continua amb els valors restaurats
Durant l'execució:
1. L'usuari canvia darkMode = true
2. Settings detecta el canvi
3. Guarda automàticament al disc
Tancament de l'aplicació:
1. Settings guarda tots els canvis pendents
2. L'app es tanca
ConfigPage.qml:
import QtQuick
import QtQuick.Controls
import rpsconfig
Page {
Column {
spacing: 20
// Switch per al tema
Switch {
text: "Mode fosc"
checked: ThemeManager.darkMode
onToggled: {
ThemeManager.toggleTheme()
// Settings guarda automàticament!
}
}
// Switch per al so
Switch {
text: "So activat"
checked: root.soundEnabled
onToggled: {
root.soundEnabled = checked
// Settings guarda automàticament!
}
}
Text {
text: "Partides jugades: " + root.gamesPlayed
color: ThemeManager.textColor
}
}
}
# Mostra el contingut del fitxer de configuració
cat ~/.config/ExempleOrg/RPSConfig.conf
Veuràs alguna cosa com:
[General]
darkMode=true
sound=true
games=5
Usa alias sempre que sigui possible
Settings {
property alias darkMode: ThemeManager.darkMode // Millor
// En comptes de:
// property bool darkMode: ThemeManager.darkMode // Pitjor
}
Agrupa settings relacionades
Settings {
category: "Appearance" // Grup al fitxer de configuració
property alias darkMode: ThemeManager.darkMode
property alias fontSize: root.fontSize
}
Settings {
category: "Game"
property alias difficulty: root.difficulty
property alias gamesPlayed: root.gamesPlayed
}
Proporciona valors per defecte
property bool soundEnabled: true // Valor per defecte si no hi ha Settings
Settings {
property alias sound: root.soundEnabled
}
| Error | Causa | Solució |
|---|---|---|
| "Cannot open: img/rock.png" | Recursos no al CMakeLists.txt | Afegeix-los a RESOURCES |
| "ThemeManager is not defined" | Falta declaració singleton | Afegeix al qmldir |
| "Settings no guarda" | Falta setOrganizationName | Afegeix al main.cpp |
| Colors [undefined] | ThemeManager no és singleton | Verifica pragma Singleton |
✅ Gestió moderna de recursos sense fitxers .qrc
✅ Paths relatius dins de mòduls QML
✅ Singletons per a estat global compartit
✅ Persistència automàtica amb Settings
✅ Arquitectura modular amb components reutilitzables
Molt bé! Ara tens tots els coneixements per crear aplicacions Qt6 modernes amb gestió de recursos i persistència de dades. 🎉