Auf dieser Seite

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.

Einrichten des neuen Projekts

Einstellen des Projektstandorts

Der Qt Quick Anwendungsassistent erstellt ein Projekt, das die folgenden Quelldateien enthält:

QuelldateiZweck
CMakeLists.txtDie Projektdatei
main.cppDie Haupt-C++-Code-Datei für die Anwendung.
main.qmlDie 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

QuelldateiZweck
qtquickcontrols2.confWählt den Stil Material mit dem Thema Dark.
AlarmDialog.qmlDefiniert den Dialog zum Hinzufügen neuer Alarme.
AlarmDelegate.qmlDefiniert das Layout des Hauptbildschirms der App.
AlarmModel.qmlDefiniert die ListModel, die zum Speichern der Alarmdaten verwendet wird.
TumblerDelegate.qmlDefiniert das grafische Layout der Tumblers.
qml.qrcDie 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:

Einstellen der 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.

Unterschiedliche Weckeinstellungen für verschiedene Tage

Wenn Sie einen Alarm anklicken, wird root.checked auf true gesetzt, wodurch die Felder des Detailbildschirms sichtbar werden.

visible: root.checked

Wenn 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

Beispielprojekt @ code.qt.io

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.