Erste Schritte mit der Programmierung unter Qt Quick: Eine Alarm-Anwendung
Ein Tutorial für „ Qt Quick “ anhand einer Wecker-Anwendung.
Dieses Tutorial zeigt, wie man eine einfache Wecker-App entwickelt, und dient als Einführung in „ Qt Quick “ und „ Qt Quick Controls “.
In diesem Tutorial können Sie Alarme eingeben, bearbeiten oder löschen. Ein Alarm kann zu einem bestimmten Datum ausgelöst werden, und Sie können festlegen, dass er an einer Reihe aufeinanderfolgender Tage wiederholt wird. Diese Anwendung ähnelt der Alarm-App, die üblicherweise auf einem Android-Smartphone zu finden ist.
Ausführen des Beispiels
Sie können das Beispiel wie folgt ausführen:
- Qt Creator
Öffnen Sie den Modus „ Welcome “ und wählen Sie das Beispiel unter Examples aus. Weitere Informationen finden Sie unter Qt Creator: Tutorial: Erstellen und Ausführen.
- Qt Extension for Visual Studio Code
Führen Sie den Befehl „ Qt: Open Qt examples “ über „ Command Palette “ aus und wählen Sie das Beispiel aus der Liste aus. Weitere Informationen finden Sie unter Qt Extension for Visual Studio Code: Tutorial: Erstellen und Ausführen.
Erstellen des Alarms-Projekts
In diesem Abschnitt wird gezeigt, wie das Projekt in „ Qt Creator “ erstellt wird. Es werden die von „ Qt Creator “ automatisch generierten Dateien sowie die beiden Dateien erläutert, die der Programmierer in „ Qt Creator “ oder einem anderen Editor erstellen muss. Die beiden letztgenannten Dateien sind im Quellcode dieses Tutorials enthalten.
Hinweis: Der UI-Text in Qt Creator und der Inhalt der generierten Dateien hängen von der von Ihnen verwendeten Version von Qt Creator ab.
Qt Creator
Das Einrichten eines neuen Projekts in „ Qt Creator “ wird durch einen Assistenten unterstützt, der Sie Schritt für Schritt durch den Projekterstellungsprozess führt. Der Assistent fordert Sie auf, die für diesen bestimmten Projekttyp erforderlichen Einstellungen einzugeben, und legt das Projekt für Sie an.
Um das Projekt „Alarms“ zu erstellen, wählen Sie „ File “ > „ New Project “ > „ Application (Qt) “ > Qt Quick Application > „ Choose “. Geben Sie im Feld „ Name “ den Begriff „alarms“ ein und folgen Sie den Anweisungen des Assistenten. Verwenden Sie „ Qt Quick Application (compact)“, wenn Sie andere Build-Systeme als CMake oder Qt-Versionen unter 6 verwenden möchten.


Der Assistent für die Anwendung „ Qt Quick “ erstellt ein Projekt, das die folgenden Quelldateien enthält:
| Quelldatei | Zweck |
|---|---|
| CMakeLists.txt | Die Projektdatei |
| main.cpp | Die Haupt-C++-Code-Datei für die Anwendung. |
| Main.qml | Die Haupt-QML-Code-Datei für die Anwendung. In dieser Datei instanziieren wir unsere benutzerdefinierten QML-Typen (AlarmDialog, AlarmModel, AlarmDelegate und TumblerDelegate). |
Der Assistent generiert den Code in der unten stehenden Datei „main.cpp“. Dieser Codeblock aktiviert die High-DPI-Skalierung und deklariert „ app “ sowie „ engine “. Die Engine lädt anschließend unsere Haupt-QML-Datei.
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QObject::connect(
&engine, &QQmlApplicationEngine::objectCreationFailed, &app,
[]() { QCoreApplication::exit(-1); }, Qt::QueuedConnection);Zusätzliche Quelldateien
| Quelldatei | Zweck |
|---|---|
qtquickcontrols2.conf | Wählt den Stil „ Material “ mit dem Thema „ Dark “ aus. |
AlarmDialog.qml | Definiert den Dialog zum Hinzufügen neuer Alarme. |
AlarmDelegate.qml | Definiert das Layout des Hauptbildschirms der App. |
AlarmModel.qml | Definiert den „ ListModel “, der zum Speichern der Alarmdaten verwendet wird. |
TumblerDelegate.qml | Definiert das grafische Layout der Tumblers. |
qml.qrc | Die Ressourcendatei, die die Namen der Quelldateien enthält, mit Ausnahme von „main.cpp“ und der Projektdatei. |
qtquickcontrols2.conf
Der folgende Ausschnitt zeigt, wie das „ Dark “-Design im „ Material “-Stil festgelegt wird:
[Controls]
Style=Material
[Material]
Theme=Dark
Accent=RedMain.qml
mainWindow, ein QML-Typ von „ ApplicationWindow “, ist das Stammelement in dieser App.
ApplicationWindow {
id: window
width: 400
height: 500
visible: trueDer „ ListView “ unter „ alarmListView “ kombiniert die Daten aus „ alarmModel “ mit dem in „ alarmDelegate “ definierten Layout.
ListView {
id: alarmListView
anchors.fill: parent
model: AlarmModel {}
delegate: AlarmDelegate {}
}Neue Alarme können durch Klicken auf „ RoundButton “ ( addAlarmButton) hinzugefügt werden. Durch Klicken darauf wird der Bildschirm „ Dialog “ ( alarmDialog) geöffnet.
RoundButton {
id: addAlarmButton
text: "+"
anchors.bottom: alarmListView.bottom
anchors.bottomMargin: 8
anchors.horizontalCenter: parent.horizontalCenter
onClicked: alarmDialog.open()
}
AlarmDialog {
id: alarmDialog
x: Math.round((parent.width - width) / 2)
y: Math.round((parent.height - height) / 2)
alarmModel: alarmListView.model
}AlarmDialog.qml
Dieser Dialogbildschirm verfügt über ein „ RowLayout “ mit jeweils einem „ Tumbler “ für Stunden und Minuten sowie ein weiteres „ RowLayout “ mit jeweils einem „Tumbler“ für Tag, Monat und Jahr.
contentItem: RowLayout {
RowLayout {
id: rowTumbler
Tumbler {
id: hoursTumbler
model: 24
delegate: TumblerDelegate {
text: alarmDialog.formatNumber(modelData)
}
}
Tumbler {
id: minutesTumbler
model: 60
delegate: TumblerDelegate {
text: alarmDialog.formatNumber(modelData)
}
}
}
RowLayout {
id: datePicker
Layout.leftMargin: 20
readonly property var days: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Tumbler {
id: dayTumbler
function updateModel() {
// Populate the model with days of the month. For example: [0, ..., 30]
var previousIndex = dayTumbler.currentIndex
var array = []
var newDays = datePicker.days[monthTumbler.currentIndex]
for (let i = 1; i <= newDays; ++i)
array.push(i)
dayTumbler.model = array
dayTumbler.currentIndex = Math.min(newDays - 1, previousIndex)
}
Component.onCompleted: updateModel()
delegate: TumblerDelegate {
text: alarmDialog.formatNumber(modelData)
}
}
Tumbler {
id: monthTumbler
onCurrentIndexChanged: dayTumbler.updateModel()
model: 12
delegate: TumblerDelegate {
text: alarmDialog.locale.standaloneMonthName(modelData, Locale.ShortFormat)
}
}
Tumbler {
id: yearTumbler
// This array is populated with the next three years. For example: [2018, 2019, 2020]
readonly property var years: (function() {
var currentYear = new Date().getFullYear()
return [0, 1, 2].map(function(value) { return value + currentYear; })
})()
model: years
delegate: TumblerDelegate {
text: alarmDialog.formatNumber(modelData)
}
}
}
}
}Wenn Sie im Dialogfeld auf „OK“ klicken, werden die eingegebenen Daten zu „ alarmModel “ hinzugefügt:
onAccepted: {
alarmModel.append({
"hour": hoursTumbler.currentIndex,
"minute": minutesTumbler.currentIndex,
"day": dayTumbler.currentIndex + 1,
"month": monthTumbler.currentIndex + 1,
"year": yearTumbler.years[yearTumbler.currentIndex],
"activated": true,
"label": "",
"repeat": false,
"daysToRepeat": [
{ "dayOfWeek": 0, "repeat": false },
{ "dayOfWeek": 1, "repeat": false },
{ "dayOfWeek": 2, "repeat": false },
{ "dayOfWeek": 3, "repeat": false },
{ "dayOfWeek": 4, "repeat": false },
{ "dayOfWeek": 5, "repeat": false },
{ "dayOfWeek": 6, "repeat": false }
],
})
}
onRejected: alarmDialog.close()AlarmDelegate.qml
Jeder Alarm auf dem Hauptbildschirm ist ein „ ItemDelegate “. Die „ ItemDelegate “ „ root “ enthält alle Felder des Hauptbildschirms und des Detailbildschirms. Die Felder des Detailbildschirms sind erst sichtbar, nachdem auf einen Alarm geklickt wurde, d. h. wenn „ root.checked “ den Wert „ true “ annimmt.
ItemDelegate {
id: root
width: parent.width
checkable: true
required property int index
required property int hour
required property int minute
required property int day
required property int month
required property int year
required property bool activated
required property string label
required property bool repeat
required property list<var> daysToRepeat
onClicked: ListView.view.currentIndex = index
contentItem: ColumnLayout {
spacing: 0
RowLayout {
ColumnLayout {
id: dateColumn
readonly property date alarmDate: new Date(
root.year, root.month - 1, root.day, root.hour, root.minute)
Label {
id: timeLabel
font.pixelSize: (Qt.application as Application).font.pixelSize * 2
text: dateColumn.alarmDate.toLocaleTimeString(root.locale, Locale.ShortFormat)
}
RowLayout {
Label {
id: dateLabel
text: dateColumn.alarmDate.toLocaleDateString(root.locale, Locale.ShortFormat)
}
Label {
id: alarmAbout
text: "⸱ " + root.label
visible: root.label.length > 0 && !root.checked
}
}
}
Item {
Layout.fillWidth: true
}
Switch {
checked: root.activated
Layout.alignment: Qt.AlignTop
onClicked: root.activated = checked
}
}
CheckBox {
id: alarmRepeat
text: qsTr("Repeat")
checked: root.repeat
visible: root.checked
onToggled: root.repeat = checked
}
Flow {
visible: root.checked && root.repeat
Layout.fillWidth: true
Repeater {
id: dayRepeater
model: root.daysToRepeat
delegate: RoundButton {
required property int dayOfWeek
required property bool repeat
text: Qt.locale().dayName(dayOfWeek, Locale.NarrowFormat)
flat: true
checked: repeat
checkable: true
Material.background: checked ? Material.accent : "transparent"
onToggled: repeat = checked
}
}
}
TextField {
id: alarmDescriptionTextField
placeholderText: qsTr("Enter description here")
cursorVisible: true
visible: root.checked
text: root.label
onTextEdited: root.label = text
}
Button {
id: deleteAlarmButton
text: qsTr("Delete")
visible: root.checked
onClicked: root.ListView.view.model.remove(root.ListView.view.currentIndex, 1)
}
}
}AlarmModel.qml
Diese QML-Datei enthält die Definition von alarmModel, dem ListModel, der die Alarmdaten verwaltet.
Sie erstellt fünf „ ListElements “ mit Beispielalarmen.
import QtQuick
// Populate the model with some sample data.
ListModel {
id: alarmModel
ListElement {
hour: 6
minute: 0
day: 2
month: 8
year: 2018
activated: true
label: "Wake up"
repeat: true
daysToRepeat: [
ListElement { dayOfWeek: 0; repeat: false },
ListElement { dayOfWeek: 1; repeat: false },
ListElement { dayOfWeek: 2; repeat: false },
ListElement { dayOfWeek: 3; repeat: false },
ListElement { dayOfWeek: 4; repeat: false },
ListElement { dayOfWeek: 5; repeat: false },
ListElement { dayOfWeek: 6; repeat: false }
]
}
ListElement {
hour: 6
minute: 0
day: 3
month: 8
year: 2018
activated: true
label: "Wake up"
repeat: true
daysToRepeat: [
ListElement { dayOfWeek: 0; repeat: true },
ListElement { dayOfWeek: 1; repeat: true },
ListElement { dayOfWeek: 2; repeat: true },
ListElement { dayOfWeek: 3; repeat: true },
ListElement { dayOfWeek: 4; repeat: true },
ListElement { dayOfWeek: 5; repeat: false },
ListElement { dayOfWeek: 6; repeat: false }
]
}
ListElement {
hour: 7
minute: 0
day: 3
month: 8
year: 2018
activated: false
label: "Exercise"
repeat: true
daysToRepeat: [
ListElement { dayOfWeek: 0; repeat: true },
ListElement { dayOfWeek: 1; repeat: true },
ListElement { dayOfWeek: 2; repeat: true },
ListElement { dayOfWeek: 3; repeat: true },
ListElement { dayOfWeek: 4; repeat: true },
ListElement { dayOfWeek: 5; repeat: true },
ListElement { dayOfWeek: 6; repeat: true }
]
}
ListElement {
hour: 5
minute: 15
day: 1
month: 9
year: 2018
activated: true
label: ""
repeat: false
daysToRepeat: [
ListElement { dayOfWeek: 0; repeat: false },
ListElement { dayOfWeek: 1; repeat: false },
ListElement { dayOfWeek: 2; repeat: false },
ListElement { dayOfWeek: 3; repeat: false },
ListElement { dayOfWeek: 4; repeat: false },
ListElement { dayOfWeek: 5; repeat: false },
ListElement { dayOfWeek: 6; repeat: false }
]
}
ListElement {
hour: 5
minute: 45
day: 3
month: 9
year: 2018
activated: false
label: ""
repeat: false
daysToRepeat: [
ListElement { dayOfWeek: 0; repeat: false },
ListElement { dayOfWeek: 1; repeat: false },
ListElement { dayOfWeek: 2; repeat: false },
ListElement { dayOfWeek: 3; repeat: false },
ListElement { dayOfWeek: 4; repeat: false },
ListElement { dayOfWeek: 5; repeat: false },
ListElement { dayOfWeek: 6; repeat: false }
]
}
}TumblerDelegate.qml
TumblerDelegate definiert die grafischen Eigenschaften der Tumblers.
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Material
Text {
required property int modelData
required property int index
text: modelData
color: Tumbler.tumbler.Material.foreground
font: Tumbler.tumbler.font
opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}Neue Alarme hinzufügen
Am unteren Rand des Startbildschirms sehen Sie eine Schaltfläche zum Hinzufügen von Alarmen. Klicken Sie darauf, um den Dialog „Neuen Alarm hinzufügen“ zu öffnen.
RoundButton {
id: addAlarmButton
text: "+"
anchors.bottom: alarmListView.bottom
anchors.bottomMargin: 8
anchors.horizontalCenter: parent.horizontalCenter
onClicked: alarmDialog.open()
}Der Dialog für neue Alarme:

Alle Felder werden mithilfe von QML-Typen „ Tumbler “ ausgefüllt. Wenn Sie auf „ OK “ klicken, werden die in den Tumblern ausgewählten Werte in „ alarmModel “ geschrieben.
contentItem: RowLayout {
RowLayout {
id: rowTumbler
Tumbler {
id: hoursTumbler
model: 24
delegate: TumblerDelegate {
text: alarmDialog.formatNumber(modelData)
}
}
Tumbler {
id: minutesTumbler
model: 60
delegate: TumblerDelegate {
text: alarmDialog.formatNumber(modelData)
}
}
}
RowLayout {
id: datePicker
Layout.leftMargin: 20
readonly property var days: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Tumbler {
id: dayTumbler
function updateModel() {
// Populate the model with days of the month. For example: [0, ..., 30]
var previousIndex = dayTumbler.currentIndex
var array = []
var newDays = datePicker.days[monthTumbler.currentIndex]
for (let i = 1; i <= newDays; ++i)
array.push(i)
dayTumbler.model = array
dayTumbler.currentIndex = Math.min(newDays - 1, previousIndex)
}
Component.onCompleted: updateModel()
delegate: TumblerDelegate {
text: alarmDialog.formatNumber(modelData)
}
}
Tumbler {
id: monthTumbler
onCurrentIndexChanged: dayTumbler.updateModel()
model: 12
delegate: TumblerDelegate {
text: alarmDialog.locale.standaloneMonthName(modelData, Locale.ShortFormat)
}
}
Tumbler {
id: yearTumbler
// This array is populated with the next three years. For example: [2018, 2019, 2020]
readonly property var years: (function() {
var currentYear = new Date().getFullYear()
return [0, 1, 2].map(function(value) { return value + currentYear; })
})()
model: years
delegate: TumblerDelegate {
text: alarmDialog.formatNumber(modelData)
}
}
}
}
}Alarme bearbeiten
Wenn Sie auf einen bestimmten Alarm klicken, können Sie ihn im Detailbild bearbeiten.

Durch Klicken auf einen Alarm wird „ root.checked “ auf „ true “ gesetzt, wodurch die Felder des Detailbildschirms sichtbar werden.
visible: root.checkedWenn der Alarm auch an anderen Tagen ausgelöst werden soll, aktivieren Sie das Kontrollkästchen „ alarmRepeat “. Der Repeater zeigt für jeden Wochentag ein aktivierbares Kontrollkästchen „ RoundButton “ an.
Flow {
visible: root.checked && root.repeat
Layout.fillWidth: true
Repeater {
id: dayRepeater
model: root.daysToRepeat
delegate: RoundButton {
required property int dayOfWeek
required property bool repeat
text: Qt.locale().dayName(dayOfWeek, Locale.NarrowFormat)
flat: true
checked: repeat
checkable: true
Material.background: checked ? Material.accent : "transparent"
onToggled: repeat = checked
}
}
}Wenn Sie die Beschreibung des Alarms ändern, wird dies anschließend auf dem Hauptbildschirm angezeigt.
TextField {
id: alarmDescriptionTextField
placeholderText: qsTr("Enter description here")
cursorVisible: true
visible: root.checked
text: root.label
onTextEdited: root.label = text
}Alarme löschen
Der Detailbildschirm (siehe oben) verfügt über eine Schaltfläche zum Löschen von Alarmen. Wenn „ onClicked “ gesendet wird, wird der aktuelle „ ListElement “ aus „ alarmModel “ gelöscht.
Button {
id: deleteAlarmButton
text: qsTr("Delete")
visible: root.checked
onClicked: root.ListView.view.model.remove(root.ListView.view.currentIndex, 1)
}Nächste Schritte
Die App enthält keinen Code zum Hinzufügen von Ton oder Vibration zum Alarm und speichert die Alarme auch nicht in einem bestimmten Format oder einer Datenbank. Stellen Sie sich der Herausforderung, diese Funktionen dem Projekt hinzuzufügen. Die Speicherung der Daten könnte im JSON-Format erfolgen.
Quelldateien
Siehe auch JSON-Unterstützung in Qt, Alle Qt-Beispiele sowie Beispiele und Tutorials unterQt Quick .
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.