forked from qt-creator/qt-creator
Added a new Qt for MCUs macro and modified a number of related topics accordingly. Task-number: QDS-9609 Change-Id: I6506a9cb6671c29d5b164d53cb01c827639ecb16 Reviewed-by: Mats Honkamaa <mats.honkamaa@qt.io>
257 lines
11 KiB
Plaintext
257 lines
11 KiB
Plaintext
// Copyright (C) 2021 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
|
|
|
/*!
|
|
\example washingMachineUI
|
|
\ingroup studioexamples
|
|
|
|
\title Washing Machine UI
|
|
\brief Illustrates how to create a UI that can be run both on the desktop
|
|
and on MCUs.
|
|
|
|
\image washingmachineui.png "Start screen"
|
|
|
|
\e {Washing Machine UI} is a control panel application for washing machines.
|
|
The application contains the following screens:
|
|
|
|
\list
|
|
\li \e Start displays a start button
|
|
\li \e Presets displays recently used wash programs
|
|
\li \e {Quick Start} enables users to either specify settings or
|
|
start the selected wash program
|
|
\li \e {Wash Program} displays wash program settings
|
|
\li \e Running displays the progress of the wash program
|
|
\endlist
|
|
|
|
Users select buttons to navigate between the screens.
|
|
We use \l{glossary-connection}{connections} to determine which
|
|
screen to open when users select a particular button and \l{glossary-state}
|
|
{states} to show the screens. We use the \l{Creating Timeline Animations}
|
|
{timeline} to create progress indicators for buttons and the \e Running
|
|
screen.
|
|
|
|
In addition, all screens contain a small clock component that displays
|
|
the current time. We implement a \e TimeDate JavaScript object to
|
|
support this feature on \l{https://doc.qt.io/QtForMCUs/qtul-qmltypes.html}
|
|
{\QMCU}, which does not support the \l Date component at the time of
|
|
writing.
|
|
|
|
\section1 Creating an Application for MCUs
|
|
|
|
We use the \uicontrol {\QMCU Application} project template to create
|
|
an application for MCUs, which support only a subset of the preset
|
|
\l{glossary-component}{components}. We select \uicontrol File >
|
|
\uicontrol {New Project} > \uicontrol {\QMCU Application} >
|
|
\uicontrol Choose, and follow the instructions of the wizard to create our
|
|
project.
|
|
|
|
This way, only the components and properties supported on MCUs are visible
|
|
in \l Components and \l Properties, and we won't accidentally
|
|
add unsupported components to our UI or specify unsupported properties for
|
|
supported components. For more information, see \l{Creating Projects}.
|
|
|
|
In addition, the wizard template creates a generic \c CMakeLists.txt file
|
|
that we can use to configure and build our example application for running
|
|
it on MCUs.
|
|
|
|
\note This example has been tested to run using \QMCU versions since
|
|
1.6. You cannot run it on older versions. Also, at the time of writing,
|
|
\QMCU only supports Qt 5.
|
|
|
|
\section1 Creating Screens
|
|
|
|
For this example, we used an external tool to design the UI and then
|
|
exported and imported our design into \QDS as assets and components
|
|
using \QB, as instructed in \l{Exporting from Design Tools}. While
|
|
exporting, we only picked components supported by \QMCU to use
|
|
for our components. For the button components, we mostly use the
|
|
\l {basic-image}{Image}, \l Text, and \l {Mouse Area} components. For the
|
|
screen background, we use the \l {basic-rectangle}{Rectangle} component.
|
|
|
|
The text might look different on the desktop and MCUs because on the
|
|
desktop we use dynamic font loading, whereas on MCUs fonts are compiled
|
|
into application sources. Therefore, the text will always be Maven Pro
|
|
on MCUs, whereas on the desktop you'd need to have Maven Pro installed
|
|
for it to be used. Usually, you will see the system default font instead.
|
|
|
|
We also created a more complicated component called \e MultSegmentArc
|
|
that we use to indicate that a button is pressed.
|
|
|
|
Alternatively, you could create the screens from scratch in \QDS
|
|
by selecting \uicontrol File > \uicontrol {New File} >
|
|
\uicontrol {Qt Quick Files}. While designing the screens, you can
|
|
move reusable components into separate files. For more information,
|
|
see \l{Using Components}.
|
|
|
|
\section1 Creating a Progress Indicator
|
|
|
|
We create a reusable MultSegmentArc component, and use it in our
|
|
\e Bigbutton and \e Smallbutton components to indicate the button
|
|
press progress. The component displays an animated arc around a
|
|
button when it is pressed. On the desktop, users only need to click
|
|
once to run the animation to the end, whereas on MCUs, they need
|
|
to keep the button pressed until the animation finishes.
|
|
|
|
\image washingmachineui-progress-indicator.png "Button progress indicator"
|
|
|
|
Our component is composed of four blocks, into which the arc segments will
|
|
rotate to indicate progress. To build it, we use \l{basic-image}{Image}
|
|
components that have pictures of four segments of an arc as sources and
|
|
\l{basic-rectangle}{Rectangle} components that mask the segments of the
|
|
arc that should be hidden until they have rotated into place. For the
|
|
\e Smallbutton component, we override the images with pictures of smaller
|
|
arc segments that will fit nicely around the small button.
|
|
|
|
\image washingmachineui-multisegmentarc.png "MultSegmentArc component"
|
|
|
|
We animate the rotation properties of the arc segments to rotate each of
|
|
them into the next block, one after another.
|
|
|
|
We use this component instead of the \l Arc component, which is not supported
|
|
on MCUs.
|
|
|
|
We can now add a timeline animation to make the arc move around the button
|
|
when the button is pressed. In the \uicontrol Timeline view, we select the
|
|
\inlineimage icons/plus.png
|
|
button to add a 1000-frame timeline to the \e root of the component.
|
|
We'll use the default values for all other fields.
|
|
|
|
\image washingmachineui-timeline-settings.png "Timeline settings"
|
|
|
|
First, we select the initial arc segment, \e arcSegment1, in
|
|
\l Navigator to display its properties in \uicontrol Properties.
|
|
In \uicontrol {Geometry - 2D} > \uicontrol Rotation, we select
|
|
\inlineimage icons/action-icon.png
|
|
(\uicontrol Actions), and then select \uicontrol {Insert Keyframe} to
|
|
insert a keyframe that we can animate in the \uicontrol Timeline view.
|
|
|
|
\image washingmachineui-insert-keyframe.png "Inserting keyframe for Rotation property"
|
|
|
|
To start recording a rotation animation on the timeline, we check that the
|
|
playhead is at frame 0 and then select the \inlineimage icons/recordfill.png
|
|
(\uicontrol {Auto Key (K)}) button (or press \key k).
|
|
|
|
First, we set the rotation at frame 0 to -90 in \uicontrol Properties >
|
|
\uicontrol {Geometry - 2D} > \uicontrol Rotation. Next, we move the playhead
|
|
to frame 250 and set the rotation to 0.
|
|
|
|
When we deselect the record button to stop recording the timeline, the
|
|
new timeline appears in the view.
|
|
|
|
\image washingmachineui-timeline.png "Rotation animation in Timeline view"
|
|
|
|
We now repeat the above steps to add keyframes for the other arc
|
|
segments and to animate their rotation property to move from -90
|
|
at frame 0 to 0 at frame 500 (\e arcSegment2), 750 (\e arcSegment3),
|
|
and 1000 (\e arcSegment4).
|
|
|
|
When we move the playhead in \uicontrol Timeline, we can see the rotation
|
|
animation in the \l {2D} view.
|
|
|
|
\image washingmachineui-multsegmentarc.gif "Rotation animation in the 2D view"
|
|
|
|
\section1 Creating States
|
|
|
|
In our UI, we use connections and states to move between screens. First,
|
|
we specify the application workflow in \e ApplicationFlow.qml. When the
|
|
file is open in the \uicontrol {2D} view, we drag-and-drop the components
|
|
that define the screens in the application from \uicontrol Components to
|
|
\uicontrol Navigator or the \uicontrol {2D} view: \e StartScreen,
|
|
\e SettingsScreen, \e PresetsScreen, and \e RunningScreen.
|
|
|
|
\image washingmachineui-application-flow.png "startScreen component in different views"
|
|
|
|
Because we will use states to display one screen at a time, depending on
|
|
the choices users make, we can place all the screens on top of each other
|
|
in the top-left corner of the root component.
|
|
|
|
Then, we open the \uicontrol States view to create the \e start,
|
|
\e settings, \e presets, and \e running \l{Working with States}{states} for
|
|
displaying a particular screen by selecting \uicontrol {Create New State}.
|
|
|
|
\image washingmachineui-states.png "States view"
|
|
|
|
In \QMCU, states work differently from Qt Quick, and therefore we
|
|
sometimes use \c when conditions to determine the state to apply, and
|
|
sometimes switch states using signals and JavaScript expressions.
|
|
|
|
\section1 Connecting Buttons to State Changes
|
|
|
|
In each file that defines a screen, we connect signals to the
|
|
button components to change to a particular state when users select
|
|
buttons.
|
|
|
|
Some signals are predefined for the \l {Mouse Area} component, some we have to
|
|
add ourselves. For example, let's look at the start button that we use
|
|
in \e StartScreen.ui.qml. First, we use the \l{Code} view
|
|
to create the \c startClicked signal:
|
|
|
|
\quotefromfile washingMachineUI/StartScreen.ui.qml
|
|
\skipto Item {
|
|
\printuntil startClicked
|
|
|
|
Then, we select the mouse area for the start button, \e startMA,
|
|
in \uicontrol Navigator. On the \uicontrol Connections tab in the
|
|
\l {Connections} view, we select the \inlineimage icons/plus.png
|
|
(\uicontrol Add) button to connect the \c onClicked() signal handler
|
|
of the button to the \c startClicked() signal.
|
|
|
|
\image washingmachineui-connections.png "Connections view"
|
|
|
|
Then, in \e ApplicationView.qml, we specify that the \c startClicked()
|
|
signal changes the application state to \e presets:
|
|
|
|
\quotefromfile washingMachineUI/ApplicationFlow.qml
|
|
\skipto Item {
|
|
\printuntil }
|
|
|
|
We have to do it this way because we are developing for MCUs. We have to
|
|
use either \c when conditions or set the state directly through code,
|
|
which overrides \c when conditions. Otherwise, we could just select the
|
|
action to change to the state that we want in the \uicontrol Action field.
|
|
|
|
We create similar connections between button components and signals in the
|
|
other screens to apply other actions that move users to other screens.
|
|
|
|
For more information, see \l {Connecting Components to Signals}.
|
|
|
|
\section1 Showing the Current Time
|
|
|
|
The \l Date component is not supported on \QMCU, and the
|
|
\l{https://doc.qt.io/QtForMCUs/qtul-javascript-environment.html}
|
|
{implementation of the JavaScript \c Date()} object returns elapsed
|
|
time since when the application was started instead of the current
|
|
date and time, as specified in ECMAScript specification.
|
|
|
|
To get around this limitation on the desktop, we create our own component
|
|
in the \e Timedate.qml file with some properties that we will need later
|
|
to get the current time in hours and minutes:
|
|
|
|
\quotefromfile washingMachineUI/Timedate.qml
|
|
\skipto Item {
|
|
\printuntil minInt
|
|
|
|
On MCUs, we will unfortunately still see the elapsed time since when the
|
|
application was started. However, this is useful on the \e Running screen
|
|
for indicating the progress of the selected wash program.
|
|
|
|
We use a \l Text component to create a label with formatted text:
|
|
|
|
\printuntil }
|
|
|
|
We use an \l Item as a logic module to get and format current time
|
|
information:
|
|
|
|
\printuntil }
|
|
|
|
We use the \c updateTime() function to display the current time in
|
|
hours and minutes:
|
|
|
|
\printuntil }
|
|
|
|
To use two digits for hours and minutes, we use the \c hrsStr, \c minStr,
|
|
\c hrsInt, and \c minInt properties to add extra zeros for values below
|
|
10. This way, the clock will display the time as \c 08:00 instead as \c 8:0,
|
|
for example.
|
|
*/
|