30/11/2025
- Kom godt i gang med Qt og QML til moderne applikationer
- Oprettelse af et nyt projekt i Qt Creator
- Implementering af kernelogik i C++
- Tilføjelse af QML-brugergrænsefladen
- Initialisering af QML-grænsefladen og fuldskærmstilstand
- Strukturering af kode med komponenter (QML)
- Kommunikation mellem QML og C++
- Tilføjelse af animationer og visuel feedback
- Oprettelse af 'About' dialogen i QML
- Implementering af kernefunktionalitet: Tilfældige billeder og effekter
- Opsummering og videreudvikling
Kom godt i gang med Qt og QML til moderne applikationer
Qt er et fleksibelt og kraftfuldt framework til at skabe applikationer på tværs af platforme. QML er nu en integreret del af Qt og tilbyder et markup-sprog, der giver fuldstændig frihed i udviklingen af brugergrænseflader. Denne artikel vil guide dig gennem processen med at oprette en simpel, men funktionel, Qt GUI-applikation ved hjælp af både Qt C++ og QML. Vi vil bygge en applikation kaldet '4Toddler', som starter i fuldskærm, viser tilfældige billeder med en fyrværkerieffekt og understøtter lydeffekter, alt imens den har to knapper til 'Om' og 'Luk' placeret i øverste højre hjørne.

Oprettelse af et nyt projekt i Qt Creator
Før vi kan begynde at kode, skal du sikre dig, at du har Qt SDK installeret. Hvis ikke, kan du downloade det fra Qt download-side. Når installationen er fuldført, skal du starte Qt Creator. Følg disse trin for at oprette et nyt projekt:
- Gå til File -> New File or Project.
- I dialogboksen skal du vælge Qt C++ Project -> Qt Gui Application og klikke på Choose….
- Angiv et projeknavn (f.eks. '4Toddler') og vælg en placering til projektmappen. Klik derefter på Next.
- I det næste vindue skal du fjerne markeringen i Generate form, da vi vil skrive vores brugergrænseflade med QML. Klik på Next.
- Afslut projektet ved at klikke på Finish.
Nu har du et grundlæggende skelet til din applikation, klar til at tilføje logik og design.
Implementering af kernelogik i C++
For at kunne vise et QML-interface i vores applikation, skal vi tilføje qt-declarative modulet. Dette modul leverer den nødvendige widget. Åbn projektfilen (f.eks. '4Toddler.pro') og tilføj 'declarative' til din QT linje:
QT += core gui declarative
Derefter skal vi ændre basisklassen for vores hovedvindue. Erstat QMainWindow med QDeclarativeView og inkluder den nødvendige header:
#include <QDeclarativeView> class MainWindow: public QDeclarativeView { // ... din kode her ... }; Du skal også fjerne initialiseringen af QMainWindow fra din MainWindow konstruktør, da QDeclarativeView håndterer dette anderledes:
MainWindow::MainWindow(QWidget *parent) { Init(); // Vi kalder vores egen Init-funktion } Indtil videre vil applikationen vise et tomt vindue, da vi endnu ikke har initialiseret eller oprettet vores QML-interface.
Tilføjelse af QML-brugergrænsefladen
Lad os nu tilføje den fil, der vil definere vores brugergrænseflade. Højreklik på projektet i 'Projects' vinduet, vælg Add New..., og under Qt sektionen, vælg Qt QML File. Klik på Choose….
Angiv filnavnet som 'main.qml' og klik Next og derefter Finish.
Qt Creator vil oprette og åbne 'main.qml' filen. Som standard indeholder den et Rectangle element. Dette bliver roden af vores brugergrænseflade. Lad os tilføje nogle egenskaber til dette element for at definere baggrundsfarve og størrelse:
Rectangle { id: canvas // ID for at tilgå elementet color: "black" // Sæt baggrundsfarven til sort anchors.fill: parent // Fyld hele forældre-elementet focus: true // Tillad elementet at modtage fokus } På dette tidspunkt har vi kun en sort baggrund. Nu skal vi forbinde dette QML-interface med vores C++ kode.
Initialisering af QML-grænsefladen og fuldskærmstilstand
For at indlæse vores QML-fil og konfigurere applikationen korrekt, skal vi definere en ny metode i mainwindow.h:
void Init();
Og implementere den i mainwindow.cpp. Her sætter vi også fokuspolitik, ændrer størrelses-tilstanden og indlæser vores QML-fil:
#include <QDeclarativeView> #include <QDir> #include <QStringList> #include <QSound> void MainWindow::Init() { QString contentPath; #ifdef QT_DEBUG // Sti til projektmappen i debug-versionen contentPath = "D:/MyProjects/QT/4Toddler"; // Tilpas denne sti til din projektsti #else // Sti til applikationsmappen i release-versionen contentPath = QApplication::applicationDirPath(); #endif // Gem stien til senere brug m_ContentPath = contentPath; setFocusPolicy(Qt::StrongFocus); setResizeMode(QDeclarativeView::SizeRootObjectToView); setSource(QUrl::fromLocalFile(contentPath + "/main.qml")); } Husk at tilføje en medlemsvariabel QString m_ContentPath; i din MainWindow klasse i mainwindow.h.
For at få applikationen til at starte i fuldskærm, skal vi ændre linjen i main.cpp, der viser vinduet:
// Erstat w.show(); med: w.showFullScreen();
Strukturering af kode med komponenter (QML)
For at gøre vores kode genbrugelig, vil vi oprette en QML-komponent til vores knapper. Opret en ny QML-fil kaldet WindowButton.qml. Filnavne, der starter med et stort bogstav, indikerer, at de definerer en QML-komponent.
import QtQuick 2.0 Image { id: button property alias source: imageSource // Gør kilden til en alias property var callback: function() {} // Egenskab til at kalde en funktion ved klik Image { // Indlejret Image for at vise kilden id: imageSource anchors.fill: parent } MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor // Ændrer musemarkøren til en hånd onClicked: callback() } } Nu kan vi bruge denne komponent i vores main.qml til at tilføje 'About' og 'Close' knapperne:
import QtQuick 2.0 Rectangle { id: canvas color: "black" anchors.fill: parent focus: true // Knapper placeret i en række øverst til højre Row { anchors.right: parent.right anchors.top: parent.top anchors.rightMargin: 10 anchors.topMargin: 10 spacing: 5 WindowButton { id: aboutButton source: "qrc:/images/about.png" // Angiv sti til billedfil (skal tilføjes til ressourcer) callback: { aboutDialog.visible = true } } WindowButton { id: closeButton source: "qrc:/images/exit.png" // Angiv sti til billedfil (skal tilføjes til ressourcer) callback: { window.Quit(); // Kalder Quit-funktionen i C++ } } } // ... resten af din main.qml ... } Bemærk: Billederne 'about.png' og 'exit.png' skal tilføjes som ressourcer til dit projekt. Højreklik på projektet i Qt Creator, vælg Add New..., og vælg Qt Resource File. Tilføj derefter billedfilerne til denne ressourcefil.

Kommunikation mellem QML og C++
For at knappen 'Close' kan lukke applikationen, skal vi implementere en Quit funktion i vores MainWindow klasse. Først tilføjer vi funktionen til mainwindow.h og markerer den med Q_INVOKABLE, så den kan kaldes fra QML:
// I MainWindow.h #include <QObject> class MainWindow: public QDeclarativeView { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); Q_INVOKABLE void Quit(); // Gør Quit-funktionen tilgængelig fra QML private: QString m_ContentPath; void Init(); }; Og implementeringen i mainwindow.cpp:
// I MainWindow.cpp void MainWindow::Quit() { QApplication::quit(); } For at gøre MainWindow objektet tilgængeligt i QML, skal vi registrere det i vores Init funktion:
// I MainWindow::Init() rootContext()->setContextProperty("window", this); Nu kan vi kalde window.Quit() fra vores QML-kode, som vist i eksemplet ovenfor for closeButton.
Tilføjelse af animationer og visuel feedback
For at give brugerne visuel feedback, når de interagerer med knapperne, kan vi tilføje tilstande og animationer til vores WindowButton.qml komponent:
import QtQuick 2.0 Image { id: button property alias source: imageSource property var callback: function() {} property bool pressed: false // Tilføj en 'pressed' egenskab Image { id: imageSource anchors.fill: parent } MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor hoverEnabled: true // Aktiver hover-effekter onEntered: { if (!pressed) button.opacity = 0.7 // Gør knappen lidt gennemsigtig, når musen er over den } onExited: { if (!pressed) button.opacity = 1.0 // Gendan fuld opacitet, når musen forlader } onClicked: { pressed = true // Sæt 'pressed' til true ved klik callback() // Tilføj en lille forsinkelse før nulstilling af 'pressed' for at give visuel feedback // Dette kan gøres med en Timer i QML eller ved at kalde en funktion fra C++ } } states: [ State { name: "normal" PropertyChanges { target: button; opacity: 1.0 } }, State { name: "hovered" PropertyChanges { target: button; opacity: 0.7 } }, State { name: "clicked" PropertyChanges { target: button; opacity: 0.5 } } ] // Overgang mellem tilstande Behavior on opacity { NumberAnimation { duration: 100 } } // Håndter reset af 'pressed' tilstand (simuleret her) // Ideelt set ville dette håndteres med en Timer eller en C++ callback Timer { interval: 200; onTriggered: { pressed = false; button.opacity = 1.0; } running: button.pressed // Start timeren, når knappen trykkes ned repeat: false } } I main.qml opdateres callback'en for aboutButton til at vise en dialog:
// I main.qml, inden i Row elementet: WindowButton { id: aboutButton source: "qrc:/images/about.png" callback: { aboutDialog.visible = true // Gør dialogen synlig } } Oprettelse af 'About' dialogen i QML
Lad os oprette en simpel 'About' dialog i QML. Tilføj følgende til din main.qml fil:
Rectangle { id: aboutDialog width: parent.width height: parent.height color: "transparent" visible: false // Som standard er dialogen usynlig // Semi-transparent baggrund Rectangle { anchors.fill: parent color: "gray" opacity: 0.5 } // Selve dialogboksen Rectangle { id: dialogBox width: 360 height: 230 color: "white" border.color: "gray" anchors.centerIn: parent Text { text: "4 Toddler App\nVersion 1.0\nUdviklet med Qt og QML" font.bold: true font.pixelSize: 20 anchors.centerIn: parent horizontalAlignment: Text.AlignHCenter } } // Gør det muligt at lukke dialogen ved at klikke udenfor MouseArea { anchors.fill: parent onClicked: { aboutDialog.visible = false; } } } Denne dialog er nu integreret i din main.qml. Når 'About' knappen klikkes, sættes aboutDialog.visible til true, hvilket gør den synlig. Klik på baggrunden lukker den igen.
Implementering af kernefunktionalitet: Tilfældige billeder og effekter
Lad os nu implementere den centrale del af applikationen: visning af tilfældige billeder med en fyrværkerieffekt og lydeffekter. Først opretter vi en genbrugelig komponent til billederne, kaldet Block.qml:
import QtQuick 2.0 import QtLabs.particles 2.0 Item { // Brug Item som base for fleksibilitet id: blockItem property alias source: imageSource.source // Alias til billedkilden property bool remove: false property bool show: false // Billede der skal vises Image { id: imageSource width: 100 // Juster størrelse efter behov height: 100 anchors.centerIn: parent // Centrer billedet inden i Item fillMode: Image.Stretch } // Fyrværkeri-effekt Particles { id: fireworks width: parent.width * 2 // Dæk et større område height: parent.height * 2 anchors.centerIn: parent emissionRate: 0 lifeSpan: 700 lifeSpanDeviation: 600 angle: 0 angleDeviation: 360 velocity: 100 velocityDeviation: 30 // Kilden til partiklerne (tilfældige billeder) source: "qrc:/images/Stars/" + getRandomStarImage() // Funktion til at vælge et tilfældigt stjerne-billede function getRandomStarImage() { var images = ["red.png", "blue.png", "green.png", "white.png", "yellow.png"]; var idx = Math.floor(Math.random() * images.length); return images[idx]; } } // Tilstande for elementet states: [ State { name: "remove" when: remove == true PropertyChanges { target: blockItem; opacity: 0 } StateChangeScript { script: blockItem.destroy(1000) } // Slet elementet efter 1 sekund }, State { name: "show" when: show == true PropertyChanges { target: blockItem; opacity: 1 } StateChangeScript { script: fireworks.burst(50) } // Start fyrværkeri ved visning } ] // Animation for opacitet Behavior on opacity { NumberAnimation { duration: 300 } } } Husk at oprette en mappe kaldet images/Stars i din ressourcefil og tilføje billederne 'red.png', 'blue.png', 'green.png', 'white.png', 'yellow.png'.
Nu skal vi implementere tastaturhåndteringen. Opret en ny JavaScript-fil kaldet main.js:
// main.js var component = Qt.createComponent("Block.qml"); // Opret en komponent-reference var maxBlocksCount = 10; // Maksimalt antal elementer på skærmen var blocksArray = new Array(); // Array til at holde styr på elementer // Funktion til at oprette et nyt element function createNewBlock(x, y) { if (component.status !== Component.Ready) { console.log("Component not ready!"); return false; } // Fjern ældste element, hvis vi har for mange if (blocksArray.length >= maxBlocksCount) { removeOldestBlock(); } var newBlock = component.createObject(canvas, { "x": x, "y": y, "source": "qrc:/images/Icons/" + window.randomIcon }); if (newBlock === null) { console.log("Failed to create new block object."); return false; } newBlock.show = true; // Sæt tilstanden til 'show' blocksArray.push(newBlock); window.playSound(); // Afspil lydeffekt return true; } // Funktion til at fjerne det ældste element function removeOldestBlock() { if (blocksArray.length > 0) { var blockToRemove = blocksArray.shift(); // Fjern første element fra array blockToRemove.remove = true; // Sæt tilstanden til 'remove' } } // Håndterer tastatur-input function handleKey(event) { if (event.isAutoRepeat === false) { var x = Math.floor(Math.random() * canvas.width); var y = Math.floor(Math.random() * canvas.height); createNewBlock(x, y); } } I main.qml skal vi importere denne JavaScript-fil og tilknytte handleKey funktionen til tastatur-events:
import QtQuick 2.0 import "main.js" as Main // Importer JavaScript-filen Rectangle { id: canvas // ... eksisterende kode ... // Håndter tastatur-input på hovedelementet Keys.onPressed: { Main.handleKey(event); } // Tilføj Block komponenten her, men den bliver instansieret via JavaScript // Det er bedre at lade JavaScript oprette objekterne dynamisk } Nu mangler vi at definere randomIcon egenskaben og PlaySound metoden i C++. Tilføj dette til mainwindow.h:
// I MainWindow.h #include <QObject> #include <QDeclarativeView> #include <QDir> #include <QStringList> #include <QSound> class MainWindow: public QDeclarativeView { Q_OBJECT Q_PROPERTY(QString randomIcon READ RandomIcon NOTIFY randomIconChanged) public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); // Destruktor for at rydde op Q_INVOKABLE void Quit(); Q_INVOKABLE void PlaySound(); // Gør PlaySound tilgængelig fra QML QString RandomIcon(); signals: // Signal for at underrette QML om ændring void randomIconChanged(); private: QString m_ContentPath; void Init(); }; Og implementeringen i mainwindow.cpp:
// I MainWindow.cpp #include <QDebug> // I konstruktøren eller Init() for at initialisere tilfældighed MainWindow::MainWindow(QWidget *parent): QDeclarativeView(parent) { qsrand(QTime::currentTime().msec()); // Initialiser random seed Init(); } // Implementering af RandomIcon QString MainWindow::RandomIcon() { QStringList iconFilesList; QDir directory(m_ContentPath + "/Icons/"); // Sti til ikonerne QStringList filters; filters << "*.png"; // Søg efter PNG-filer directory.setNameFilters(filters); iconFilesList = directory.entryList(QDir::Files); if (iconFilesList.isEmpty()) { qWarning() << "Ingen ikoner fundet i " << m_ContentPath + "/Icons/"; return "default.png"; // Returner en standard hvis ingen ikoner findes } int fileIdx = qrand() % iconFilesList.count(); return iconFilesList.at(fileIdx); } // Implementering af PlaySound void MainWindow::PlaySound() { QStringList soundFilesList; QDir directory(m_ContentPath + "/Sounds/"); // Sti til lydeffekter QStringList filters; filters << "*.wav"; // Søg efter WAV-filer directory.setNameFilters(filters); soundFilesList = directory.entryList(QDir::Files); if (soundFilesList.isEmpty()) { qWarning() << "Ingen lydeffekter fundet i " << m_ContentPath + "/Sounds/"; return; } int fileIdx = qrand() % soundFilesList.count(); QString soundFile = m_ContentPath + "/Sounds/" + soundFilesList.at(fileIdx); QSound::play(soundFile); } Du skal også tilføje en mappe Icons og Sounds til dit projekt (i samme mappe som din main.qml eller tilføje dem til ressourcefilen) og placere PNG-billeder og WAV-lyde der. Du skal også kalde emit randomIconChanged();, når du vil opdatere det tilfældige ikon, hvis det er nødvendigt, men i dette eksempel bruges det direkte ved oprettelse af blokken.
Til sidst, for at sikre at fyrværkeri-effekten vises, skal vi foretage en lille ændring i Block.qml. Inkluder dette i "show" tilstanden:
// I Block.qml, i "show" tilstanden: State { name: "show" when: show == true PropertyChanges { target: blockItem; opacity: 1 } StateChangeScript { script: fireworks.burst(50) } // Start fyrværkeri ved visning } Nu kan du kompilere og køre din applikation. Når du trykker på en tast, vil et tilfældigt billede dukke op med en fyrværkerieffekt og en lydeffekt. 'About' knappen viser dialogen, og 'Close' knappen lukker applikationen.
Opsummering og videreudvikling
Denne guide har vist, hvordan man opretter en simpel GUI-applikation ved hjælp af Qt og QML. Vi har dækket projektopsætning, C++ logik, QML brugergrænseflade, kommunikation mellem de to, animationer og effekter. Selvom '4Toddler' applikationen er simpel, demonstrerer den de grundlæggende principper for moderne app-udvikling med Qt.
Du kan udvide denne applikation ved at tilføje flere funktioner, såsom:
- Flere interaktive elementer i QML.
- En mere kompleks logik i C++.
- Integration med en database.
- Bedre håndtering af fejl og ressourcer.
- Tilføjelse af flere sprogunderstøttelse.
Måske kan dette projekt udvikle sig til en kommerciel app, der f.eks. er rettet mod børn med læringsindhold om bogstaver, tal, former og farver.
Ofte Stillede Spørgsmål (FAQ)
- Hvad er forskellen på Qt og QML?
- Qt er et C++ framework til cross-platform udvikling, mens QML er et deklarativt sprog til at definere brugergrænseflader, som integreres med Qt.
- Hvordan tilføjer jeg billeder og lyde til mit Qt-projekt?
- Den bedste metode er at bruge Qt's ressource-system (.qrc-filer), som gør det nemt at inkludere filer direkte i din eksekverbare fil.
- Kan jeg bruge andre animationsmetoder end
Behavior? - Ja, Qt Quick tilbyder også `PropertyAnimation` og `Transition` elementer, som giver mere detaljeret kontrol over animationer.
- Hvordan håndterer jeg komplekse brugerinteraktioner?
- For komplekse interaktioner kan du bruge `MouseArea` og `Keys` elementer i QML, og forbinde dem til C++ funktioner for mere avanceret logik.
Denne artikel er baseret på en tutorial fra Intel AppUp(SM) developer program.
Hvis du vil læse andre artikler, der ligner Opret en Qt GUI-applikation med QML, kan du besøge kategorien Teknologi.
