Erste Schritte in der Programmierung mit Qt Quick: Eine Alarmanwendung
Ein Tutorium für Qt Quick, das auf einer Alarmanwendung basiert.
Dieses Tutorial zeigt, wie man eine einfache Alarmanwendung als Einführung in Qt Quick und Qt Quick Controls entwickelt.
In diesem Tutorium können Sie Alarme eingeben, bearbeiten oder löschen. Ein Alarm kann an einem bestimmten Datum ausgelöst werden, und Sie können ihn so einstellen, dass er an einer Reihe von aufeinander folgenden Tagen wiederholt wird. Diese Anwendung ähnelt der Alarmanwendung, die normalerweise auf einem Android-Handy zu finden ist.
Ausführen des Beispiels
Zum Ausführen des Beispiels von Qt Creatorzu starten, öffnen Sie den Modus Welcome und wählen Sie das Beispiel von Examples. Weitere Informationen finden Sie unter Qt Creator: Tutorial: Erstellen und Ausführen.
Erstellen des Alarmprojekts
Dieser Abschnitt zeigt, wie das Projekt in Qt Creator erstellt wird. Er beschreibt die Dateien, die automatisch von Qt Creator erzeugt werden, und die beiden Dateien, die der Programmierer in Qt Creator oder einem anderen Editor erstellen muss. Die beiden letztgenannten Dateien sind im Quellcode dieses Lehrgangs enthalten.
Hinweis: Der UI-Text in Qt Creator und der Inhalt der generierten Dateien hängen von der verwendeten Qt Creator Version ab.
Qt Creator
Das Einrichten eines neuen Projekts in Qt Creator wird durch einen Assistenten unterstützt, der Sie Schritt für Schritt durch die Projekterstellung führt. Der Assistent fordert Sie auf, die für den jeweiligen Projekttyp erforderlichen Einstellungen einzugeben, und erstellt das Projekt für Sie.
Um das Projekt "Alarme" zu erstellen, wählen Sie File > New Project > Application (Qt) > Qt Quick Application > Choose. Geben Sie Alarme in das Feld Name ein, und folgen Sie den Anweisungen des Assistenten. Verwenden Sie Qt Quick Application (compact), wenn Sie andere Build-Systeme als CMake oder Qt-Versionen kleiner als 6 verwenden möchten.


Der Qt Quick Anwendungsassistent 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 QML-Hauptcodedatei für die Anwendung. In dieser Datei werden unsere benutzerdefinierten QML-Typen (AlarmDialog, AlarmModel, AlarmDelegate und TumblerDelegate) instanziiert. |
Der Assistent generiert den Code in der Datei main.cpp unten. Dieser Codeblock aktiviert die hohe DPI-Skalierung und deklariert app und engine. Die Engine lädt dann 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. |
AlarmDialog.qml | Definiert den Dialog zum Hinzufügen neuer Alarme. |
AlarmDelegate.qml | Definiert das Layout des Hauptbildschirms der App. |
AlarmModel.qml | Definiert die ListModel, die 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 man das Thema Dark im Stil Material einstellt:
[Controls] Style=Material [Material] Theme=Dark Accent=Red
Main.qml
mainWindowEin ApplicationWindow QML-Typ ist das Wurzelelement in dieser Anwendung.
ApplicationWindow { id: window width: 400 height: 500 visible: true
Die ListView alarmListView kombiniert die Daten von 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. Wenn Sie darauf klicken, öffnet sich ein Dialog Bildschirm alarmDialog.
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 Dialog hat ein RowLayout mit je einem Tumbler für Stunden und Minuten und ein RowLayout mit je 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 in dem Dialog 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 im Hauptbildschirm ist ein ItemDelegate. Der ItemDelegate root enthält alle Felder des Hauptbildschirms und des Detailbildschirms. Die Felder des Detailbildschirms sind nur sichtbar, wenn ein Alarm angeklickt wurde, d.h. wenn root.checked true ist.
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, der ListModel, die 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 }
Eingabe von neuen Alarmen
Am unteren Rand des Startbildschirms befindet sich eine Schaltfläche zum Hinzufügen von Alarmen. Klicken Sie darauf, um den Dialog zum Hinzufügen neuer Alarme zu öffnen.
RoundButton { id: addAlarmButton text: "+" anchors.bottom: alarmListView.bottom anchors.bottomMargin: 8 anchors.horizontalCenter: parent.horizontalCenter onClicked: alarmDialog.open() }
Das Dialogfeld für neue Alarme:

Alle Felder werden mit Tumbler QML-Typen eingegeben. Wenn Sie OK drücken, 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) } } } } }
Bearbeiten von Alarmen
Wenn Sie auf einen bestimmten Alarm klicken, können Sie ihn im Detailbildschirm bearbeiten.

Wenn Sie einen Alarm anklicken, wird root.checked auf true gesetzt, wodurch die Felder des Detailbildschirms sichtbar werden.
visible: root.checkedWenn Sie möchten, dass der Alarm auch an anderen Tagen ausgelöst wird, aktivieren Sie alarmRepeat. Der Repeater zeigt dann für jeden Wochentag eine ankreuzbare 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 }
Löschen von Alarmen
Der Detailbildschirm (siehe oben) verfügt über eine Schaltfläche zum Löschen von Alarmen. Wenn onClicked ausgesendet wird, wird der aktuelle ListElement von 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 verfügt weder über einen Code zum Hinzufügen von Ton oder Vibration zum Alarm, noch speichert sie die Alarme in einem Format oder einer Datenbank. Fordern Sie sich selbst heraus, indem Sie dem Projekt diese Funktionen hinzufügen. Die Speicherung der Daten könnte im JSON-Format erfolgen.
Quelldateien
Siehe auch JSON-Unterstützung in Qt, Alle Qt-Beispiele, und Qt Quick Beispiele und Tutorials.
© 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.