Auf dieser Seite

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:

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.

Einrichten des neuen Projekts

Festlegen des Projektstandorts

Der Assistent für die Anwendung „ Qt Quick “ 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 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

QuelldateiZweck
qtquickcontrols2.confWählt den Stil „ Material “ mit dem Thema „ Dark “ aus.
AlarmDialog.qmlDefiniert den Dialog zum Hinzufügen neuer Alarme.
AlarmDelegate.qmlDefiniert das Layout des Hauptbildschirms der App.
AlarmModel.qmlDefiniert den „ ListModel “, der 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 das „ Dark “-Design im „ Material “-Stil festgelegt wird:

[Controls]
Style=Material
[Material]
Theme=Dark
Accent=Red
Main.qml

mainWindow, ein QML-Typ von „ ApplicationWindow “, ist das Stammelement in dieser App.

ApplicationWindow {
    id: window
    width: 400
    height: 500
    visible: true

Der „ 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:

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

Unterschiedliche Weckereinstellungen für verschiedene Tage

Durch Klicken auf einen Alarm wird „ root.checked “ auf „ true “ gesetzt, wodurch die Felder des Detailbildschirms sichtbar werden.

visible: root.checked

Wenn 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

Beispielprojekt @ code.qt.io

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.