Erste Schritte in der Programmierung mit Qt Quick
Ein Tutorium für Qt Quick basierend auf einer Alarmanwendung.
Dieses Tutorial zeigt, wie man eine einfache Alarmanwendung als Einführung in Qt Quick und Qt Quick Controls entwickelt.
Diese Anwendung ähnelt der Alarmanwendung, die normalerweise auf einem Android-Handy zu finden ist. Mit ihren Funktionen 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 Folgetagen wiederholt wird.
Auf dem Hauptbildschirm wird die Liste der gespeicherten Alarme angezeigt:
Im Detailbildschirm können Sie vorhandene Alarme bearbeiten oder löschen:
Das Dialogfenster dient zum Hinzufügen neuer Alarme. Er öffnet sich, wenn Sie auf das "+" RoundButton am unteren Rand des Hauptbildschirms klicken:
Die Quelldateien befinden sich im qtdoc-Repository. Sie können die Qt-Quellen entweder aus dem Qt-Projekt holen oder sie als Teil von Qt installieren. Die Anwendung ist auch in der Beispielliste des Willkommensmodus von Qt Creator verfügbar.
Erstellen des Alarms-Projekts
In diesem Abschnitt wird gezeigt, wie das Projekt in Qt Creator erstellt wird. Es wird auf die Dateien eingegangen, die automatisch von Qt Creator generiert werden, sowie auf 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.
Der Anwendungsassistent 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 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
mainWindow
Ein 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 property alias dayTumbler: dayTumbler property alias monthTumbler: monthTumbler property alias yearTumbler: yearTumbler 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 (var 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 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 property alias dayTumbler: dayTumbler property alias monthTumbler: monthTumbler property alias yearTumbler: yearTumbler 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 (var 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.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
ausgegeben 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) }
Zusammenfassung
Die App hat keinen Code, um dem Alarm einen Ton oder eine Vibration hinzuzufügen, noch speichert sie die Alarme in irgendeinem Format oder einer Datenbank. Vielleicht wäre es ein interessantes Programmierprojekt, diese Funktionen hinzuzufügen. Das Speichern der Daten könnte schnell und einfach im JSON-Format erfolgen.
Siehe auch JSON-Unterstützung in Qt.
© 2025 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.