From 1df70118583e069bde41d03bc9753cef949b3e39 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 3 Aug 2018 14:21:05 +0200 Subject: [PATCH] Doc: tutorial Get Started with Qt Quick Task-number: QTBUG-68739 Change-Id: Ib14e4eb4c20583af2be9198539077f1be5ae471a Reviewed-by: Edward Welbourne Reviewed-by: Venugopal Shivashankar --- doc/config/qtdoc.qdocconf | 2 +- .../getting-started/gettingstartedqml.qdoc | 1262 +++-------------- doc/src/images/addalarms.png | Bin 0 -> 5231 bytes doc/src/images/alarms2.png | Bin 0 -> 24310 bytes doc/src/images/alarms3.png | Bin 0 -> 14194 bytes doc/src/images/detailscreen.png | Bin 0 -> 10657 bytes doc/src/images/mainscreen.png | Bin 0 -> 7056 bytes examples/tutorials/alarms/AlarmDelegate.qml | 142 ++ examples/tutorials/alarms/AlarmDialog.qml | 168 +++ examples/tutorials/alarms/AlarmModel.qml | 152 ++ examples/tutorials/alarms/TumblerDelegate.qml | 62 + examples/tutorials/alarms/alarms.pro | 29 + examples/tutorials/alarms/main.cpp | 65 + examples/tutorials/alarms/main.qml | 86 ++ examples/tutorials/alarms/qml.qrc | 10 + .../tutorials/alarms/qtquickcontrols2.conf | 5 + 16 files changed, 948 insertions(+), 1035 deletions(-) create mode 100644 doc/src/images/addalarms.png create mode 100644 doc/src/images/alarms2.png create mode 100644 doc/src/images/alarms3.png create mode 100644 doc/src/images/detailscreen.png create mode 100644 doc/src/images/mainscreen.png create mode 100644 examples/tutorials/alarms/AlarmDelegate.qml create mode 100644 examples/tutorials/alarms/AlarmDialog.qml create mode 100644 examples/tutorials/alarms/AlarmModel.qml create mode 100644 examples/tutorials/alarms/TumblerDelegate.qml create mode 100644 examples/tutorials/alarms/alarms.pro create mode 100644 examples/tutorials/alarms/main.cpp create mode 100644 examples/tutorials/alarms/main.qml create mode 100644 examples/tutorials/alarms/qml.qrc create mode 100644 examples/tutorials/alarms/qtquickcontrols2.conf diff --git a/doc/config/qtdoc.qdocconf b/doc/config/qtdoc.qdocconf index 623cf0d6b..5a346f4f7 100644 --- a/doc/config/qtdoc.qdocconf +++ b/doc/config/qtdoc.qdocconf @@ -88,7 +88,7 @@ exampledirs += \ excludedirs += \ ../src/snippets -examplesinstallpath = demos +examplesinstallpath = qhp.projects = QtDoc diff --git a/doc/src/getting-started/gettingstartedqml.qdoc b/doc/src/getting-started/gettingstartedqml.qdoc index cd6cedf16..f66f1a01e 100644 --- a/doc/src/getting-started/gettingstartedqml.qdoc +++ b/doc/src/getting-started/gettingstartedqml.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -26,1063 +26,257 @@ ****************************************************************************/ /*! - \page gettingstartedqml.html + \example tutorials/gettingstartedqtquick \title Getting Started Programming with Qt Quick + \brief A tutorial for Qt Quick based on an alarms application - Welcome to the world of \b QML, the declarative UI language. In this Getting - Started guide, we will create a simple text editor application using QML. - After reading this guide, you should be ready to develop your own applications - using QML and Qt C++. + This tutorial shows how to develop a simple alarm application as + an introduction to Qt Quick and Qt Quick Controls2. - \section1 QML to Build User Interfaces + This application is similar to the alarm application usually + found on an Android phone. Its features let you enter, edit, + or delete alarms. An alarm can trigger on a given date, and you + can set it to repeat on a series of subsequent days. - The application we are building is a simple text editor that will load, save, - and perform some text manipulation. This guide will consist of two parts. The - first part will involve designing the application layout and behaviors using - declarative language in QML. For the second part, file loading and saving will - be implemented using Qt C++. Using - \l {The Meta-Object System}{Qt's Meta-Object System}, we can expose C++ functions - as properties that \l{QML Object Types}{QML object types} can use. Utilizing QML and Qt C++, we can - efficiently decouple the interface logic from the application logic. + The main screen shows the list of saved alarms: - \image qml-texteditor5_editmenu.png + \image mainscreen.png "Alarms application" - The complete source code is in the \c{examples/quick/tutorials/gettingStartedQml} - directory. If you wish to see how the finalized application looks like, you - can skip to chapter \l {Running the Text Editor}. + The detail screen lets you edit or delete existing alarms: - The C++ portion of this tutorial assumes that the reader possesses basic knowledge of - Qt's compilation procedures. + \image detailscreen.png "Detail screen" - Tutorial chapters: - \list 1 - \li \l {Defining a Button and a Menu} - \li \l {Implementing a Menu Bar} - \li \l {Building a Text Editor} - \li \l {Decorating the Text Editor} - \li \l {Extending QML using Qt C++} - \endlist + The dialog screen is used for adding new alarms. It pops up + when you click on the "+" RoundButton on the bottom of the main + screen: - Information about QML, such as syntax and features, is included in the - \l{The QML Reference}. + \image addalarms.png "Add alarms" - \section1 Defining a Button and a Menu + The source files are located in the qtdoc repository. + You can either fetch the Qt 5 sources from the Qt Project, + or install them as part of Qt 5. The application is also available + in the example list of Qt Creator's Welcome mode. - \section2 Basic Component - a Button + \section1 Creating the Alarms Project - We start our text editor by building a button. Functionally, a button has a mouse - sensitive area and a label. Buttons perform actions when a user presses the button. + This section shows how to create the project in Qt Creator. It discusses + the files generated automatically by Qt Creator, and the two files + the programmer has to create in Qt Creator or some other editor. + The latter two files are included with the source code for this + tutorial. - In QML, the basic visual item is the \l Rectangle type. The - \c Rectangle \l{QML Object Types}{QML object type} has - \l{Property Binding}{QML properties} to control its appearance and location. + \section1 Qt Creator + + Setting up a new project in Qt Creator is aided by a wizard that + guides you step-by-step through the project creation process. The + wizard prompts you to enter the settings needed for that particular + type of project and creates the project for you. + + To create the Alarms project, select \uicontrol{File} > + \uicontrol{New File or Project} > \uicontrol{Application} > + \uicontrol{Qt Quick Application - Empty} > \uicontrol{Choose}. + Type "alarms" in the \b{Name} field, and follow the instructions + of the wizard. + + \image alarms2.png "Qt Creator New File or Project dialog" + + \image alarms3.png "Project Location" + + The Qt Quick application wizard creates a project that contains + the following source files: + + \table + \header + \li Source file + \li Purpose + \row + \li alarms.pro + \li The project file + \row + \li main.cpp + \li The main C++ code file for the application. + \row + \li qml.qrc + \li The resource file, which contains the names of the + source files, except main.cpp and the project file. + \endtable + + The wizard generates the code in the main.cpp file below. + This code block enables High DPI scaling and declares \c app + and \c engine. The engine then loads our main QML file. + + \quotefromfile tutorials/alarms/main.cpp + \skipto main + \printuntil } + + \section1 Additional source files + + \table + \header + \li Source file + \li Purpose + \row + \li \c qtquickcontrols2.conf + \li Selects the \c Material style with the \c Dark theme. + \row + \li \c main.qml + \li The QML code that links AlarmDialog.qml, AlarmModel.qml, + AlarmDelegate.qml and TumblerDelegate.qml + \row + \li \c AlarmDialog.qml + \li Defines the dialog for adding new alarms. + \row + \li \c AlarmDelegate.qml + \li Defines the layout of the main screen of the app. + \row + \li \c AlarmModel.qml + \li Defines the ListModel used for storing the alarms' data. + \row + \li \c TumblerDelegate.qml + \li Defines the graphical layout of the Tumblers + \endtable + + + \section2 \c qtquickcontrols2.conf + + The following snippet shows how to set the \c Dark theme in the + \c Material style: + + \quotefile tutorials/alarms/qtquickcontrols2.conf + + \section2 \c main.qml + + \c mainWindow, an ApplicationWindow QML type, is the root item in + this app. + + \quotefromfile tutorials/alarms/main.qml + \skipto ApplicationWindow + \printuntil visible + + The ListView \c alarmListView combines the data from \c alarmModel + with the layout defined in \c alarmDelegate. + + \quotefromfile tutorials/alarms/main.qml + \skipuntil visible + \printto RoundButton + + New alarms can be added by clicking RoundButton \c addAlarmButton. + Clicking it opens a \l {Dialog: QtQuickControls2}{dialog} screen \c alarmDialog. + + \printuntil alarmDialog.open + \printuntil alarmListView.model + \printline } + + \section2 \c AlarmDialog.qml + + This dialog screen has a RowLayout with a \l {Tumbler} each for hours + and minutes, and another RowLayout with a Tumbler each for day, month, + and year. + + \quotefromfile tutorials/alarms/AlarmDialog.qml + \skipto contentItem + \printuntil "model: years" + \printuntil } + + If you click on \b OK in the dialog, the entered data will be + added to \c alarmModel: + + \quotefromfile tutorials/alarms/AlarmDialog.qml + \skipto onAccepted + \printuntil onRejected + + \section2 \c AlarmDelegate.qml + + Each alarm in the main screen is an ItemDelegate. The ItemDelegate + \c root contains all fields on the main screen and the detail + screen. The detail screen's fields are only visible after an alarm + has been clicked on, i.e. when \c root.checked is \c true. + + \quotefromfile tutorials/alarms/AlarmDelegate.qml + \skipto ItemDelegate + \printuntil /^\}/ + + \section2 \c AlarmModel.qml + + This QML file contains the definition of \c alarmModel, the ListModel + that manages the alarm data. + + It creates five \l {ListElement}{ListElements} with example alarms. + + \quotefromfile tutorials/alarms/AlarmModel.qml + \skipto import + \printuntil /^\}/ + + \section2 TumblerDelegate.qml + + TumblerDelegate defines the graphical properties of the Tumblers. + + \quotefromfile tutorials/alarms/TumblerDelegate.qml + \skipto import + \printuntil /^\}/ + + \section1 Entering new alarms + + At the bottom of the startup screen, you can see a Button for adding + alarms. Click it to open the \b {Add new alarm} dialog. + + \quotefromfile tutorials/alarms/main.qml + \skipto RoundButton + \printto AlarmDialog + + The dialog for new alarms: + + \image addalarms.png "Add alarms" + + All fields are entered using \l {Tumbler} QML types. If you press \c OK, + the values selected in the Tumblers are written to \c alarmModel. + + \quotefromfile tutorials/alarms/AlarmDialog.qml + \skipto contentItem + \printuntil " }" + + \section1 Editing alarms + + If you click on a particular alarm, you can edit it in the detail + screen. + + \image detailscreen.png + + Clicking on an alarm sets \c root.checked to \c true, which makes + visible the fields of the detail screen. \code - import QtQuick 2.3 - - Rectangle { - id: simpleButton - color: "grey" - width: 150; height: 75 - - Text { - id: buttonLabel - anchors.centerIn: parent - text: "button label" - } - } + visible: root.checked \endcode - First, the \c {import QtQuick 2.3} statement allows the - \l{Prototyping with qmlscene}{qmlscene} tool to import the QML types we will later use. - This line must exist for every QML file. Notice that the version of Qt modules is - included in the import statement. + If you want the alarm to trigger also on other days, check \c alarmRepeat. + The Repeater will display a checkable RoundButton for each day of the week. - This simple rectangle has a unique identifier, \c simpleButton, which is bound to the - \c id property. The \c Rectangle object's properties are bound to values by listing the - property, followed by a colon, then the value. In the code sample, the color \c grey - is bound to the Rectangle's \c color property. Similarly, we bind the \c width - and \c height of the Rectangle. + \quotefromfile tutorials/alarms/AlarmDelegate.qml + \skipto Flow + \printto TextField - The \l Text type is a non-editable text field. We name this object \c buttonLabel. To set - the string content of the Text field, we bind a value to the \c text property. The label - is contained within the Rectangle and in order to center it in the middle, we assign the - \c anchors of the Text object to its parent, which is called \c simpleButton. Anchors may - bind to other items' anchors, allowing layout assignments simpler. + If you modify the description of the alarm, it will be reflected in + the main screen afterwards. - We shall save this code as \c SimpleButton.qml. Running \c qmlscene with the file as the - argument will display the grey rectangle with a text label. + \printto Button - \image qml-texteditor1_simplebutton.png + \section1 Deleting alarms - To implement the button click functionality, we can use QML's event handling. QML's event - handling is very similar to \l {Signals & Slots}{Qt's signal and slot} mechanism. Signals - are emitted and the connected slot is called. + The detail screen (see above) has a Button for deleting alarms. + When \c onClicked is emitted, the current ListElement is deleted + from \c alarmModel. - \code - Rectangle { - id: simpleButton - ... + \printuntil alarmModel.remove + \printuntil } - MouseArea { - id: buttonMouseArea + \section2 Summary - // Anchor all sides of the mouse area to the rectangle's anchors - anchors.fill: parent - // onClicked handles valid mouse button clicks - onClicked: console.log(buttonLabel.text + " clicked") - } - } - \endcode + The app has no code for adding sound or vibration to the alarm, nor does + it store the alarms in any format or database. Maybe it could be an + interesting coding project to add those features. Adding sound to this + program can be realized with \l{Qt Multimedia QML Types}. Storing the data + could be done quickly and easily in \l{JSON Support in Qt}{JSON format}. - We include a \l MouseArea object in our simpleButton. \c MouseArea objects describe - the interactive area where mouse movements are detected. For our button, we anchor the - whole \c MouseArea to its parent, which is \c simpleButton. The \c anchors.fill syntax is - one way of accessing a specific property called \c fill inside a group of properties - called \c anchors. QML uses \l {Positioning with Anchors}{anchor-based layouts} where - items can anchor to another item, creating robust layouts. + \sa {Qt Multimedia QML Types}, {JSON Support in Qt} - The \c MouseArea has many signal handlers that are called during mouse movements within - the specified \c MouseArea boundaries. One of them is \c onClicked and it is called - whenever the acceptable mouse button is clicked, the left click being the default. We - can bind actions to the onClicked handler. In our example, \c console.log() outputs text - whenever the mouse area is clicked. The function \c console.log() is a useful tool for - debugging purposes and for outputting text. - - The code in \c SimpleButton.qml is sufficient to display a button on the screen and - output text whenever it is clicked with a mouse. - - \code - Rectangle { - id: button - ... - - property color buttonColor: "lightblue" - property color onHoverColor: "gold" - property color borderColor: "white" - - signal buttonClick() - - onButtonClick: { - console.log(buttonLabel.text + " clicked") - } - - MouseArea{ - id: buttonMouseArea - onClicked: buttonClick() - hoverEnabled: true - onEntered: parent.border.color = onHoverColor - onExited: parent.border.color = borderColor - } - - // Determines the color of the button by using the conditional operator - color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor - } - \endcode - - A fully functioning button is in \c Button.qml. The code snippets in this article - have some code omitted, denoted by ellipses because they were either introduced - earlier in the previous sections or irrelevant to the current code discussion. - - Custom properties are declared using the \c {property type name} syntax. In the - code, the property \c buttonColor, of type \c color, is declared and bound to - the value \c{"lightblue"}. The \c buttonColor is later used in a conditional - operation to determine the button's fill color. Note that property value - assignment is possible using the \c= equals sign, in addition to value binding - using the \c : colon character. Custom properties allow internal items to be - accessible outside of the Rectangle's scope. There are basic - \l{QML Basic Types}{QML types} such as \c int, \c string, \c real, as well as - a type called \c variant. - - By binding the \c onEntered and \c onExited signal handlers to colors, the - button's border will turn yellow when the mouse hovers above the button and - reverts the color when the mouse exits the mouse area. - - A \c buttonClick() signal is declared in \c Button.qml by placing the \c signal - keyword in front of the signal name. All signals have their handlers automatically - created, their names starting with \c on. As a result, the \c onButtonClick is - \c buttonClick's handler. The \c onButtonClick is then assigned an action to - perform. In our button example, the \c onClicked mouse handler will simply call - \c onButtonClick, which displays a text. The \c onButtonClick enables outside - objects to access the \c {Button}'s mouse area easily. For example, items may - have more than one \c MouseArea declarations and a \c buttonClick signal can - make the distinction between the several \c MouseArea signal handlers better. - - We now have the basic knowledge to implement items in QML that can handle - basic mouse movements. We created a \c Text label inside a \c Rectangle, - customized its properties, and implemented behaviors that respond to mouse - movements. This idea of creating QML objects within objects is repeated - throughout the text editor application. - - This button is not useful unless used as a component to perform an action. - In the next section, we will soon create a menu containing several of these - buttons. - - \image qml-texteditor1_button.png - - \section2 Creating a Menu Page - - Up to this stage, we covered how to create objects and assign behaviors inside - a single QML file. In this section, we will cover how to import QML types and how - to reuse some of the created components to build other components. - - Menus display the contents of a list, each item having the ability to perform an action. - In QML, we can create a menu in several ways. First, we will create a menu containing - buttons which will eventually perform different actions. The menu code is in - \c FileMenu.qml. - - \code - import QtQuick 2.3 // Import the main Qt QML module - import "folderName" // import the contents of a folder - import "script.js" as Script // Import a Javascript file and name it as Script - \endcode - - The syntax shown above shows how to use the \c import keyword. This is required to - use JavaScript files, or QML files that are not within the same directory. Since - \c Button.qml is in the same directory as \c FileMenu.qml, we do not need to import - the \c Button.qml file to use it. We can directly create a \c Button object by declaring - \c Button{}, similar to a \c Rectangle{} declaration. - - \code - In FileMenu.qml: - - Row { - anchors.centerIn: parent - spacing: parent.width / 6 - - Button { - id: loadButton - buttonColor: "lightgrey" - label: "Load" - } - Button { - buttonColor: "grey" - id: saveButton - label: "Save" - } - Button { - id: exitButton - label: "Exit" - buttonColor: "darkgrey" - - onButtonClick: Qt.quit() - } - } - \endcode - - In \c FileMenu.qml, we declare three \c Button objects. They are declared - inside a \l Row type, a positioner that will position its children - along a vertical row. The \c Button declaration resides in Button.qml, - which is the same as the one we used in the previous section. - New property bindings can be declared within the newly created buttons, - effectively overwriting the properties set in \c Button.qml. The button - called \c exitButton will quit and close the window when it is clicked. - Note that the signal handler \c onButtonClick in \c Button.qml will be - called in addition to the \c onButtonClick handler in \c exitButton. - - \image qml-texteditor1_filemenu.png - - The \c Row declaration is declared in a \c Rectangle, creating a rectangle - container for the row of buttons. This additional rectangle creates an indirect - way of organizing the row of buttons inside a menu. - - The declaration of the edit menu is very similar at this stage. The menu has - buttons that have the labels: \c Copy, \c Paste, and \c {Select All}. - - \image qml-texteditor1_editmenu.png - - Armed with our knowledge of importing and customizing previously made - components, we may now combine these menu pages to create a menu bar, - consisting of buttons to select the menu, and look at how we may structure - data using QML. - - \section1 Implementing a Menu Bar - - Our text editor application will need a way to display menus using a menu bar. - The menu bar will switch the different menus and the user can choose which menu - to display. Menu switching implies that the menus need more structure than - merely displaying them in a row. QML uses models and views to structure data - and display the structured data. - - \section2 Using Data Models and Views - - QML has different \l{QML Data Models}{data views} that display - \l{QML Data Models}{data models}. Our menu bar will display the menus in a list, - with a header that displays a row of menu names. The list of menus are declared - inside a \l ObjectModel. The \c ObjectModel type contains items that already are - displayable, such as \c Rectangle objects. Other model types, like the - \l ListModel type, need a delegate to display their data. - - We declare two visual items in the \c menuListModel, the \c FileMenu and the - \c EditMenu. We customize the two menus and display them in a \l ListView. - The \c MenuBar.qml file contains the QML declarations and a simple edit menu is - defined in \c EditMenu.qml. - - \code - ObjectModel { - id: menuListModel - - FileMenu { - width: menuListView.width - height: menuBar.height - color: fileColor - } - - EditMenu { - color: editColor - width: menuListView.width - height: menuBar.height - } - } - \endcode - - The \l ListView type will display a model according to a delegate. The delegate - can display the model items in a \c Row object or in a grid. Our \c menuListModel - already has visible items, therefore, we do not need to declare a delegate. - - \code - ListView { - id: menuListView - - // Anchors are set to react to window anchors - anchors.fill: parent - anchors.bottom: parent.bottom - width: parent.width - height: parent.height - - // The model contains the data - model: menuListModel - - // Control the movement of the menu switching - snapMode: ListView.SnapOneItem - orientation: ListView.Horizontal - boundsBehavior: Flickable.StopAtBounds - flickDeceleration: 5000 - highlightFollowsCurrentItem: true - highlightMoveDuration: 240 - highlightRangeMode: ListView.StrictlyEnforceRange - } - \endcode - - Additionally, \c ListView inherits from \l Flickable, making the list respond - to mouse drags and other gestures. The last portion of the code above sets - \c Flickable properties to create the desired flicking movement to our view. - In particular, the property \c highlightMoveDuration changes the duration of - the flick transition. A higher \c highlightMoveDuration value results in - slower menu switching. - - The \c ListView maintains the model items through an \c index and each visual - item in the model is accessible through the \c index, in the order of the - declaration. Changing the \c currentIndex effectively changes the highlighted - item in the \c ListView. The header of our menu bar exemplifies this effect. - There are two buttons in a row, both changing the current menu when clicked. - The \c fileButton changes the current menu to the file menu when clicked, - the \c index being \c 0 because \c FileMenu is declared first in the - \c menuListModel. Similarly, the \c editButton will change the current - menu to the \c EditMenu when clicked. - - The \c labelList rectangle has \c z value of \c 1, denoting that it is displayed - at the front of the menu bar. Items with higher \c z values are displayed in front - of items with lower \c z values. The default \c z value is \c 0. - - \code - Rectangle { - id: labelList - ... - z: 1 - - Row { - anchors.centerIn: parent - spacing: 40 - - Button { - label: "File" - id: fileButton - ... - onButtonClick: menuListView.currentIndex = 0 - } - - Button { - id: editButton - label: "Edit" - ... - onButtonClick: menuListView.currentIndex = 1 - } - } - } - \endcode - - The menu bar we just created can be flicked to access the menus or by clicking - on the menu names at the top. Switching menu screens feel intuitive and responsive. - - \image qml-texteditor2_menubar.png - - \section1 Building a Text Editor - - \section2 Declaring a TextArea - - Our text editor is not a text editor if it didn't contain an editable text area. - QML's \l TextEdit type allows the declaration of a multi-line editable text area. - \c TextEdit is different from the \l Text type, which doesn't allow the user to - directly edit the text. - - \code - TextEdit { - id: textEditor - anchors.fill: parent - width: parent.width - height: parent.height - color: "midnightblue" - focus: true - - wrapMode: TextEdit.Wrap - - onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle) - } - \endcode - - The editor has its font \c color property set and \c wrapMode set to wrap the text. - The \c TextEdit area is inside a flickable item that will scroll the text if the - text cursor is outside the visible area. The function \c ensureVisible() will - check if the cursor rectangle is outside the visible boundaries and move the - text area accordingly. QML uses Javascript syntax for its scripts, and as previously - mentioned, Javascript files can be imported and used within a QML file. - - \code - function ensureVisible(r) { - if (contentX >= r.x) - contentX = r.x; - else if (contentX + width <= r.x + r.width) - contentX = r.x + r.width - width; - if (contentY >= r.y) - contentY = r.y; - else if (contentY + height <= r.y + r.height) - contentY = r.y + r.height - height; - } - \endcode - - \section2 Combining Components for the Text Editor - - We are now ready to create the layout of our text editor using QML. The text - editor has two components, the menu bar we created and the text area. QML allows - us to reuse components, therefore making our code simpler, by importing components - and customizing when necessary. Our text editor splits the window into two; - one-third of the screen is dedicated to the menu bar and two-thirds of the screen - displays the text area. The menu bar is displayed in front of any other objects. - - \code - Rectangle { - id: screen - width: 1000 - height: 1000 - - // The screen is partitioned into the MenuBar and TextArea. - // One-third of the screen is assigned to the MenuBar - property int partition: height / 3 - - MenuBar { - id: menuBar - height: partition - width: parent.width - z: 1 - } - - TextArea { - id: textArea - anchors.bottom: parent.bottom - y: partition - color: "white" - width: parent.width - height: partition * 2 - } - } - \endcode - - By importing reusable components, our \c TextEditor code looks much simpler. - We can then customize the main application, without worrying about properties - that already have defined behaviors. Using this approach, application layouts - and UI components can be created easily. - - \image qml-texteditor3_texteditor.png - - \section1 Decorating the Text Editor - \section2 Implementing a Drawer Interface - - Our text editor looks simple and we need to decorate it. Using QML, we can declare - transitions and animate our text editor. Our menu bar is occupying one-third of the - screen and it would be nice to have it only appear when we want it. - - We can add a drawer interface, that will contract or expand the menu bar when clicked. - In our implementation, we have a thin rectangle that responds to mouse clicks. The - \c drawer, as well as the application, has two sates: the "drawer is open" state and - the "drawer is closed" state. The \c drawer item is a strip of rectangle with a small - height. There is a nested \l Image object declaring that an arrow icon will - be centered inside the drawer. The drawer assigns a state to the whole application, - with the identifier \c screen, whenever a user clicks the mouse area. - - \code - Rectangle { - id: drawer - height: 15 - - Image { - id: arrowIcon - source: "images/arrow.png" - anchors.horizontalCenter: parent.horizontalCenter - } - - MouseArea { - id: drawerMouseArea - anchors.fill: parent - - onClicked: { - if (screen.state == "DRAWER_CLOSED") - screen.state = "DRAWER_OPEN" - else if (screen.state == "DRAWER_OPEN") - screen.state = "DRAWER_CLOSED" - } - ... - } - } - \endcode - - A state is simply a collection of configurations and it is declared with the - \l State type. A list of states can be listed and bound to the \c states property. - In our application, the two states are called \c DRAWER_CLOSED and \c DRAWER_OPEN. - Item configurations are declared in \l PropertyChanges objects. In the - \c DRAWER_OPEN state, there are four items that will receive property changes. - The first target, \c menuBar, will change its \c y property to \c 0. Similarly, - the \c textArea will lower to a new position when the state is \c DRAWER_OPEN. - The \c textArea, the \c drawer, and the drawer's icon will undergo property - changes to meet the current state. - - \code - states:[ - State { - name: "DRAWER_OPEN" - PropertyChanges { target: menuBar; y: 0 } - PropertyChanges { target: textArea; y: partition + drawer.height } - PropertyChanges { target: drawer; y: partition } - PropertyChanges { target: arrowIcon; rotation: 180 } - }, - State { - name: "DRAWER_CLOSED" - PropertyChanges { target: menuBar; y: -height; } - PropertyChanges { target: textArea; y: drawer.height; height: screen.height - drawer.height } - PropertyChanges { target: drawer; y: 0 } - PropertyChanges { target: arrowIcon; rotation: 0 } - } - ] - \endcode - - State changes are abrupt and needs smoother transitions. Transitions between states - are defined using the \l Transition type, which can then bind to the item's - \c transitions property. Our text editor has a state transition whenever the state - changes to either \c DRAWER_OPEN or \c DRAWER_CLOSED. Importantly, the transition - needs a \c from and a \c to state but for our transitions, we can use the wild card - \c * symbol to denote that the transition applies to all state changes. - - During transitions, we can assign animations to the property changes. Our \c menuBar - switches position from \c {y: 0} to \c {y: -partition} and we can animate this - transition using the \l NumberAnimation type. We declare that the targets' - properties will animate for a certain duration of time and using a certain easing - curve. An easing curve controls the animation rates and interpolation behavior - during state transitions. The easing curve we chose is - \l{PropertyAnimation::easing.type}{\c Easing.OutExpo}, which slows the movement near - the end of the animation. For more information, see QML's - \l {Animation and Transitions in Qt Quick}{animation} article. - - \code - transitions: [ - Transition { - to: "*" - NumberAnimation { target: textArea; properties: "y, height"; duration: 100; easing.type:Easing.OutExpo } - NumberAnimation { target: menuBar; properties: "y"; duration: 100; easing.type: Easing.OutExpo } - NumberAnimation { target: drawer; properties: "y"; duration: 100; easing.type: Easing.OutExpo } - } - ] - \endcode - - Another way of animating property changes is by declaring a \l Behavior - type. A transition only works during state changes and \c Behavior can set an - animation for a general property change. In the text editor, the arrow has a - \c NumberAnimation animating its \c rotation property whenever the property changes. - - In \c {TextEditor.qml}: - - \code - Behavior { - NumberAnimation { property: "rotation"; easing.type: Easing.OutExpo } - } - \endcode - - Going back to our components with knowledge of states and animations, we can improve - the appearances of the components. In \c Button.qml, we can add \c color and \c scale - property changes when the button is clicked. Color types are animated using - \l ColorAnimation and numbers are animated using \l NumberAnimation. The - \c {on propertyName} syntax displayed below is helpful when targeting a single property. - - In \c {Button.qml}: - \code - ... - - color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor - Behavior on color { ColorAnimation{ duration: 55 } } - - scale: buttonMouseArea.pressed ? 1.1 : 1.0 - Behavior on scale { NumberAnimation{ duration: 55 } } - \endcode - - Additionally, we can enhance the appearances of our QML components by adding color - effects such as gradients and opacity effects. Declaring a \l Gradient object will - override the \c color property. You may declare a color in the gradient using the - \l GradientStop type. The gradient is positioned using a scale, between \c 0.0 and - \c 1.0. - - In \c {MenuBar.qml}: - - \code - gradient: Gradient { - GradientStop { position: 0.0; color: "#8C8F8C" } - GradientStop { position: 0.17; color: "#6A6D6A" } - GradientStop { position: 0.98; color: "#3F3F3F" } - GradientStop { position: 1.0; color: "#0e1B20" } - } - \endcode - - This gradient is used by the menu bar to display a gradient simulating depth. - The first color starts at \c 0.0 and the last color is at \c 1.0. - - \section3 Where to Go from Here - - We are finished building the user interface of a very simple text editor. - Going forward, the user interface is complete, and we can implement the - application logic using regular Qt and C++. QML works nicely as a prototyping - tool, separating the application logic away from the UI design. - - \image qml-texteditor4_texteditor.png - - \section2 Extending QML using Qt C++ - - Now that we have our text editor layout, we may now implement the text editor - functionalities in C++. Using QML with C++ enables us to create our application - logic using Qt. We can create a QML context in a C++ application using - \l {Integrating QML and C++}{Qt's Quick classes} and display the QML - types using a QQuickView. Alternatively, we can export our C++ code into - an extension plugin, and make it accessible to QML as a new - \l {Identified Modules}{identified module}. - When launching QML files with \l {Prototyping with qmlscene}{qmlscene}, - we only need to ensure our module is found under one of the - \l {QML Import Path}{import paths} the QML engine searches for modules - to import. For our application we shall the latter approach. This way, we can - load the QML file directly with \c qmlscene instead of running an executable. - - \section3 Exposing C++ Classes to QML - - We will be implementing file loading and saving using Qt and C++. C++ classes - and functions can be used in QML by registering them. They also needs to be - compiled as a Qt plugin and then exposed as a QML module. - - For our application, we need to create the following items: - \list 1 - \li \c Directory class that will handle directory related operations - \li \c File class which is a QObject, simulating the list of files in a directory - \li A plugin class that will register the classes to the QML context - \li Qt project file that will compile the plugin - \li A \l {Module Definition qmldir Files}{module definition qmldir file} that - defines the identifier (import URI) and content (in this case, our plugin) - to be made available by the QML module - \endlist - - \note Since Qt 5.1, \l{Qt Quick Dialogs} module provides a file dialog component - that you can use for choosing files from the local file system. For illustrative - purposes, we write our own in this tutorial. - - \section3 Building a Qt Plugin - - To build a plugin, we need to set the following in a Qt project file. First, - the necessary sources, headers, and Qt modules need to be added into our - project file. All the C++ code and project files are in the \c filedialog - directory. - - In \c {filedialog.pro}: - - \code - TEMPLATE = lib - CONFIG += qt plugin - QT += qml - - DESTDIR += ../imports/FileDialog - OBJECTS_DIR = tmp - MOC_DIR = tmp - - TARGET = filedialogplugin - - HEADERS += \ - directory.h \ - file.h \ - dialogPlugin.h - - SOURCES += \ - directory.cpp \ - file.cpp \ - dialogPlugin.cpp - \endcode - - In particular, we link the project with the \c qml module and configure it as a - \c plugin, using a \c lib template. We shall put the compiled plugin into the - parent's \c {imports/FileDialog} directory. - - \section3 Registering a Class into QML - - In \c {dialogPlugin.h}: - - \code - #include - - class DialogPlugin : public QQmlExtensionPlugin - { - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.QmlExtensionPlugin.FileDialog") - - public: - // registerTypes is inherited from QQmlExtensionPlugin - void registerTypes(const char *uri); - }; - - \endcode - - We need to export the plugin using the \l {How To Create Qt Plugins}{Q_PLUGIN_METADATA} macro. - Note that in our \c dialogPlugin.h file, we have the \l Q_OBJECT - macro at the top of our class. As well, we need to run \c qmake on the project - file to generate the necessary meta-object code. - - Our plugin class, \c {DialogPlugin}, is a subclass of \l{QQmlExtensionPlugin}. - We need to implement the inherited function, - \l {QQmlExtensionPlugin::registerTypes()}{registerTypes()}. - - In \c {DialogPlugin.cpp}: - - \code - #include "dialogPlugin.h" - #include "directory.h" - #include "file.h" - #include - - void DialogPlugin::registerTypes(const char *uri) - { - // Register the class Directory into QML as a "Directory" type version 1.0 - // @uri FileDialog - qmlRegisterType(uri, 1, 0, "Directory"); - qmlRegisterType(uri, 1, 0, "File"); - } - \endcode - - The \c registerTypes() function registers our File and Directory classes into - QML. This function needs the class name for its template, a major version number, - a minor version number, and a name for our classes. - A \c {// @uri } comment allows Qt Creator to be aware of the - registered types when editing QML files that import this module. - - \section3 Creating QML Properties in a C++ Class - - We can create QML types and properties using C++ and - \l {The Meta-Object System}{Qt's Meta-Object System}. We can implement - properties using slots and signals, making Qt aware of these properties. - These properties can then be used in QML. - - For the text editor, we need to be able to load and save files. Typically, - these features are contained in a file dialog. Fortunately, we can use - \l QDir, \l QFile, and \l QTextStream to implement directory reading and - input/output streams. - - \code - class Directory : public QObject { - Q_OBJECT - - Q_PROPERTY (int filesCount READ filesCount CONSTANT) - Q_PROPERTY (QString filename READ filename WRITE setFilename NOTIFY filenameChanged) - Q_PROPERTY (QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged) - Q_PROPERTY (QQmlListProperty files READ files CONSTANT) - ... - \endcode - - The \c Directory class uses Qt's Meta-Object System to register properties it - needs to accomplish file handling. The \c Directory class is exported as a plugin - and is useable in QML as the \c Directory type. Each of the listed properties - using the \l Q_PROPERTY() macro is a QML property. - - The \l {Q_PROPERTY()}{Q_PROPERTY} declares a property as well as its read and - write functions into Qt's Meta-Object System. For example, the \c filename - property, of type \l QString, is readable using the \c filename() - function and writable using the function \c setFilename(). Additionally, there - is a signal associated to the filename property called \c {filenameChanged()}, - which is emitted whenever the property changes. The read and write functions - are declared as \c public in the header file. - - Similarly, we have the other properties declared according to their uses. The - \c filesCount property indicates the number of files in a directory. The filename - property is set to the currently selected file's name and the loaded/saved file - content is stored in \c fileContent property. - - \code - Q_PROPERTY(QQmlListProperty files READ files CONSTANT) - \endcode - - The \c files list property is a list of all the filtered files in a directory. - The \c Directory class is implemented to filter out invalid text files; only - files with a \c .txt extension are valid. Further, \l{QList}s can be - used in QML files by declaring them as a QQmlListProperty in C++. - The templated object needs to inherit from a QObject, therefore, - the \c File class must also inherit from QObject. In the \c Directory class, - the list of \c File objects is stored in a QList called \c m_fileList. - - \code - class File : public QObject{ - - Q_OBJECT - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - - ... - }; - \endcode - - The properties can then be used in QML as part of the \c Directory object's - properties. Note that we do not have to create an identifier \c id property - in our C++ code. - - \code - Directory { - id: directory - - filesCount - filename - fileContent - files - - files[0].name - } - \endcode - - Because QML uses Javascript's syntax and structure, we can iterate through - the list of files and retrieve its properties. To retrieve the first file's - name property, we can call \c {files[0].name}. - - Regular C++ functions are also accessible from QML. The file loading and saving - functions are implemented in C++ and declared using the \l Q_INVOKABLE macro. - Alternatively, we can declare the functions as a \c slot and the functions will - be accessible from QML. - - In \c {directory.h}: - - \code - Q_INVOKABLE void saveFile(); - Q_INVOKABLE void loadFile(); - \endcode - - The \c Directory class also has to notify other objects whenever the directory - contents change. This feature is performed using a \c signal. As previously - mentioned, QML signals have a corresponding handler with their names prepended - with \c on. The signal is called \c directoryChanged and it is emitted whenever - there is a directory refresh. The refresh simply reloads the directory contents - and updates the list of valid files in the directory. QML items can then be - notified by attaching an action to the \c onDirectoryChanged signal handler. - - The \c list properties need to be explored further. This is because list - properties use callbacks to access and modify the list contents. The list - property is of type \c QQmlListProperty. Whenever the list - is accessed, the accessor function needs to return a - \c QQmlListProperty. The template type, \c File, needs to be a - \c QObject derivative. Further, to create the - \c QQmlListProperty, the list's accessor - and modifiers need to be passed to the constructor as function pointers. The list, - a \c QList in our case, also needs to be a list of \c File pointers. - - The constructor of \l QQmlListProperty is declared - as follows: - \code - QQmlListProperty (QObject *object, void *data, AppendFunction append, - CountFunction count = 0, AtFunction at = 0, ClearFunction clear = 0); - \endcode - - It takes pointers to functions that will append the list, count - the list, retrieve the item using an index, and empty the list. Only the \c append - function is mandatory. Note that the function pointers must match the definition - of \l {QQmlListProperty::AppendFunction}{AppendFunction}, - \l {QQmlListProperty::CountFunction}{CountFunction}, - \l {QQmlListProperty::AtFunction}{AtFunction}, or - \l {QQmlListProperty::ClearFunction}{ClearFunction}. - - The \c Directory class constructs a QQmlListProperty instance like this: - - \code - QQmlListProperty(this, &m_fileList, &appendFiles, &filesSize, &fileAt, &clearFilesPtr); - \endcode - - Where the parameters are pointers to following functions: - - \code - void appendFiles(QQmlListProperty *property, File *file); - File* fileAt(QQmlListProperty *property, int index); - int filesSize(QQmlListProperty *property); - void clearFilesPtr(QQmlListProperty *property); - \endcode - - To simplify our file dialog, the \c Directory class filters out invalid text - files, which are files that do not have a \c .txt extension. If a file name - doesn't have the \c .txt extension, then it won't be seen in our file dialog. - Also, the implementation makes sure that saved files have a \c .txt extension in - the file name. \c Directory uses \l {QTextStream} to read the file and to output - the file contents to a file. - - With our \c Directory object, we can retrieve the files as a list, know how many - text files is in the application directory, get the file's name and content as a - string, and be notified whenever there are changes in the directory contents. - - To build the plugin, run \c qmake on the \c filedialog.pro project file, then run - \c make to build and transfer the plugin to the \c plugins directory. - - - \section3 Importing a Plugin in QML - - The \c qmlscene tool imports files that are in the same directory as the - application. We can also create a \c qmldir file containing the locations of - content we wish to import. In this case, there is only the plugin, but other - resources (QML types, JavaScript files) can be defined in a \c qmldir as well. - - Contents of the \c qmldir file: - \code - module FileDialog - plugin filedialogplugin - \endcode - - The module we just created is called \c FileDialog, and it makes available a plugin - called \c filedialogplugin that matches the \c TARGET field in the project file. - Because we did not specify a path for the plugin, the QML engine expects to find it - in the same directory as the \c qmldir file. - - The QML types that are registered by our plugin can now be imported in QML: - - \code - import FileDialog 1.0 - - Directory { - id: directory - } - ... - \endcode - - - \section3 Integrating a File Dialog into the File Menu - - Our \c FileMenu needs to display the \c FileDialog object, containing a list of - the text files in a directory thus allowing the user to select the file by - clicking on the list. We also need to assign the save, load, and new buttons - to their respective actions. The FileMenu contains an editable text input to - allow the user to type a file name using the keyboard. - - The \c Directory object is used in the \c FileMenu.qml file and it notifies the - \c FileDialog object that the directory refreshed its contents. This notification - is performed in the signal handler, \c onDirectoryChanged. - - In \c {FileMenu.qml}: - - \code - Directory { - id: directory - filename: textInput.text - onDirectoryChanged: fileDialog.notifyRefresh() - } - \endcode - - Keeping with the simplicity of our application, the file dialog will always be - visible and will not display invalid text files, which do not have a \c .txt - extension to their filenames. - - In \c {FileDialog.qml}: - - \code - signal notifyRefresh() - onNotifyRefresh: dirView.model = directory.files - \endcode - - The \c FileDialog object will display the contents of a directory by reading its - list property called \c files. The files are used as the model of a - \l {GridView} object, which displays data items in a grid according - to a delegate. The delegate handles the appearance of the model and our file - dialog will simply create a grid with text centered in the middle. Clicking on - the file name will result in the appearance of a rectangle to highlight the file - name. The \c FileDialog is notified whenever the \c notifyRefresh signal is emitted, - reloading the files in the directory. - - In \c {FileMenu.qml}: - - \code - Button { - id: newButton - label: "New" - onButtonClick: { - textArea.textContent = "" - } - } - Button { - id: loadButton - label: "Load" - onButtonClick: { - directory.filename = textInput.text - directory.loadFile() - textArea.textContent = directory.fileContent - } - } - Button { - id: saveButton - label: "Save" - onButtonClick: { - directory.fileContent = textArea.textContent - directory.filename = textInput.text - directory.saveFile() - } - } - Button { - id: exitButton - label: "Exit" - onButtonClick: { - Qt.quit() - } - } - \endcode - - Our \c FileMenu can now connect to their respective actions. The \c saveButton - will transfer the text from the \c TextEdit onto the directory's \c fileContent - property, then copy its file name from the editable text input. Finally, the button - calls the \c saveFile() function, saving the file. The \c loadButton has a similar - execution. Also, the \c New action will empty the contents of the \c TextEdit. - - Further, the \c EditMenu buttons are connected to the \c TextEdit functions to copy, - paste, and select all the text in the text editor. - - \image qml-texteditor5_filemenu.png - - \section2 Final Text Editor Application - - \image qml-texteditor5_newfile.png - - The application can function as a simple text editor, able to accept text - and save it into a file. It can also load a file and perform text manipulation. - - \section1 Running the Text Editor - - We need to build the file dialog C++ plugin before the text editor can run. - To build it, enter the \c filedialog directory, then run \c qmake and compile - using \c make or \c nmake, depending on your platform. - - Run the text editor with \l{Prototyping with qmlscene}{qmlscene}, passing the - imports directory as a parameter so that the QML engine knows where to look for - the module that imports our file dialog plugin: - - \code - qmlscene -I ./imports texteditor.qml - \endcode - - The complete source code is in \c{examples/quick/tutorials/gettingStartedQml} directory. -*/ diff --git a/doc/src/images/addalarms.png b/doc/src/images/addalarms.png new file mode 100644 index 0000000000000000000000000000000000000000..2874d2e6ca22679a5ffbed4b3d7437783e27d317 GIT binary patch literal 5231 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

@DBDDCO4<6vk2#`{5pbZ>=<3-Fa@iT!hak1 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

K0|Yj164LkS$!-e_OI1N3WNab3Hc>BbgD7 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 literal 0 HcmV?d00001 diff --git a/doc/src/images/detailscreen.png b/doc/src/images/detailscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..bc0f0afb470b0819ab18dbeded3c7270a8acbb9b GIT binary patch literal 10657 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 Q^pAGnP)+4(MT_A702C`b5C8xG literal 0 HcmV?d00001 diff --git a/examples/tutorials/alarms/AlarmDelegate.qml b/examples/tutorials/alarms/AlarmDelegate.qml new file mode 100644 index 000000000..97ffc8676 --- /dev/null +++ b/examples/tutorials/alarms/AlarmDelegate.qml @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.4 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 + +ItemDelegate { + id: root + width: parent.width + checkable: true + + onClicked: ListView.view.currentIndex = index + + contentItem: ColumnLayout { + spacing: 0 + + RowLayout { + ColumnLayout { + id: dateColumn + + readonly property date alarmDate: new Date( + model.year, model.month - 1, model.day, model.hour, model.minute) + + Label { + id: timeLabel + font.pixelSize: Qt.application.font.pixelSize * 2 + text: dateColumn.alarmDate.toLocaleTimeString(window.locale, Locale.ShortFormat) + } + RowLayout { + Label { + id: dateLabel + text: dateColumn.alarmDate.toLocaleDateString(window.locale, Locale.ShortFormat) + } + Label { + id: alarmAbout + text: "βΈ± " + model.label + visible: model.label.length > 0 && !root.checked + } + } + } + Item { + Layout.fillWidth: true + } + Switch { + checked: model.activated + Layout.alignment: Qt.AlignTop + onClicked: model.activated = checked + } + } + CheckBox { + id: alarmRepeat + text: qsTr("Repeat") + checked: model.repeat + visible: root.checked + onToggled: model.repeat = checked + } + Flow { + visible: root.checked && model.repeat + Layout.fillWidth: true + + Repeater { + id: dayRepeater + model: daysToRepeat + delegate: RoundButton { + text: Qt.locale().dayName(model.dayOfWeek, Locale.NarrowFormat) + flat: true + checked: model.repeat + checkable: true + Material.background: checked ? Material.accent : "transparent" + onToggled: model.repeat = checked + } + } + } + + TextField { + id: alarmDescriptionTextField + placeholderText: qsTr("Enter description here") + cursorVisible: true + visible: root.checked + text: model.label + onTextEdited: model.label = text + } + Button { + id: deleteAlarmButton + text: qsTr("Delete") + width: 40 + height: 40 + visible: root.checked + onClicked: alarmModel.remove(alarmListView.currentIndex, 1) + } + } +} diff --git a/examples/tutorials/alarms/AlarmDialog.qml b/examples/tutorials/alarms/AlarmDialog.qml new file mode 100644 index 000000000..10e5a2649 --- /dev/null +++ b/examples/tutorials/alarms/AlarmDialog.qml @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 + +Dialog { + id: alarmDialog + title: "Add new alarm" + modal: true + standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel + + property AlarmModel alarmModel + + function formatNumber(number) { + return number < 10 && number >= 0 ? "0" + number : number.toString() + } + + 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() + + contentItem: RowLayout { + RowLayout { + id: rowTumbler + + Tumbler { + id: hoursTumbler + model: 24 + delegate: TumblerDelegate { + text: formatNumber(modelData) + } + } + Tumbler { + id: minutesTumbler + model: 60 + delegate: TumblerDelegate { + text: 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: formatNumber(modelData) + } + } + Tumbler { + id: monthTumbler + + onCurrentIndexChanged: dayTumbler.updateModel() + + model: 12 + delegate: TumblerDelegate { + text: window.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: formatNumber(modelData) + } + } + } + } +} diff --git a/examples/tutorials/alarms/AlarmModel.qml b/examples/tutorials/alarms/AlarmModel.qml new file mode 100644 index 000000000..6afa5db75 --- /dev/null +++ b/examples/tutorials/alarms/AlarmModel.qml @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 + +// 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 } + ] + } +} diff --git a/examples/tutorials/alarms/TumblerDelegate.qml b/examples/tutorials/alarms/TumblerDelegate.qml new file mode 100644 index 000000000..88a35a5ba --- /dev/null +++ b/examples/tutorials/alarms/TumblerDelegate.qml @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.4 + +Text { + 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 +} diff --git a/examples/tutorials/alarms/alarms.pro b/examples/tutorials/alarms/alarms.pro new file mode 100644 index 000000000..6c54c7f8f --- /dev/null +++ b/examples/tutorials/alarms/alarms.pro @@ -0,0 +1,29 @@ +QT += qml quick + +CONFIG += c++11 + +SOURCES += main.cpp + +RESOURCES += qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = $$PWD/imports + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS +TARGET = Alarms +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/examples/tutorials/alarms/main.cpp b/examples/tutorials/alarms/main.cpp new file mode 100644 index 000000000..3e1bdd84e --- /dev/null +++ b/examples/tutorials/alarms/main.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/examples/tutorials/alarms/main.qml b/examples/tutorials/alarms/main.qml new file mode 100644 index 000000000..acd541687 --- /dev/null +++ b/examples/tutorials/alarms/main.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Material 2.4 +import QtQuick.Layouts 1.11 +import QtQuick.Window 2.11 +import Qt.labs.calendar 1.0 + +ApplicationWindow { + id: window + width: 400 + height: 500 + visible: true + + ListView { + id: alarmListView + anchors.fill: parent + model: AlarmModel {} + delegate: AlarmDelegate {} + } + + 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 + } +} diff --git a/examples/tutorials/alarms/qml.qrc b/examples/tutorials/alarms/qml.qrc new file mode 100644 index 000000000..ae9ac9078 --- /dev/null +++ b/examples/tutorials/alarms/qml.qrc @@ -0,0 +1,10 @@ + + + main.qml + qtquickcontrols2.conf + TumblerDelegate.qml + AlarmModel.qml + AlarmDelegate.qml + AlarmDialog.qml + + diff --git a/examples/tutorials/alarms/qtquickcontrols2.conf b/examples/tutorials/alarms/qtquickcontrols2.conf new file mode 100644 index 000000000..3c6766599 --- /dev/null +++ b/examples/tutorials/alarms/qtquickcontrols2.conf @@ -0,0 +1,5 @@ +[Controls] +Style=Material +[Material] +Theme=Dark +Accent=Red