Quick Starter¶


4. Quick Starter


Note

Last Build: March 21, 2016 at 20:39 CET

The source code for this chapter can be found in the assets folder.

This chapter provides an overview of QML, the declarative user interface language used in Qt 5. We will discuss the QML syntax, which is a tree of elements, followed by an overview of the most important basic elements. Later we will briefly look at how to create our own elements, called components and how to transform elements using property manipulations. Towards the end we will look how to arrange elements together in a layout and finally have a look at elements where the user can provide input.

4.1. QML Syntax

Issues: Create | View

QML is a declarative language used to describe the user interface of your application. It breaks down the user interface into smaller elements, which can be combined to components. QML describes the look and the behavior of these user interface elements. This user interface description can be enriched with JavaScript code to provide simple but also more complex logic. In this perspective it follows the HTML-JavaScript pattern but QML is designed from the ground up to describe user interfaces not text-documents.

In its simplest way QML is a hierarchy of elements. Child elements inherit the coordinate system from the parent. An x,y coordinate is always relative to the parent.

../../_images/scene1.png

Let’s start with a simple example of a QML file to explain the different syntax.

// RectangleExample.qml

import QtQuick 2.5

// The root element is the Rectangle
Rectangle {
    // name this element root
    id: root

    // properties: <name>: <value>
    width: 120; height: 240

    // color property
    color: "#4A4A4A"

    // Declare a nested element (child of root)
    Image {
        id: triangle

        // reference the parent
        x: (parent.width - width)/2; y: 40

        source: 'assets/triangle_red.png'
    }

    // Another child of root
    Text {
        // un-named element

        // reference element by id
        y: triangle.y + triangle.height + 20

        // reference root element
        width: root.width

        color: 'white'
        horizontalAlignment: Text.AlignHCenter
        text: 'Triangle'
    }
}
  • The import statement imports a module in a specific version. In general you always want to import QtQuick 2.0 as your initial set of elements
  • Comments can be made using // for single line comments or /* */ for multi-line comments. Just like in C/C++ and JavaScript
  • Every QML file needs to have exactly one root element, like HTML
  • An element is declared by its type followed by { }
  • Elements can have properties, they are in the form name : value
  • Arbitrary elements inside a QML document can be accessed by using their id (an unquoted identifier)
  • Elements can be nested, meaning a parent element can have child elements. The parent element can be accessed using the parent keyword

Tip

Often you want to access a particular element by id or a parent element using the parent keyword. So it’s good practice to name your root element “root” using id: root. Then you don’t have to think about how the root element is named in your QML document.

Hint

You can run the example using the Qt Quick runtime from the command line from your OS like this:

$ $QTDIR/bin/qmlscene RectangleExample.qml

Where you need to replace the $QTDIR to the path to your Qt installation. The qmlscene executable initializes the Qt Quick runtime and interprets the provided QML file.

In Qt Creator you can open the corresponding project file and run the document RectangleExample.qml.

4.1.1. Properties

Issues: Create | View

Elements are declared by using their element name but are defined by using their properties or by creating custom properties. A property is a simple key-value pair, e.g. width : 100, text: 'Greetings', color: '#FF0000'. A property has a well-defined type and can have an initial value.

    Text {
        // (1) identifier
        id: thisLabel

        // (2) set x- and y-position
        x: 24; y: 16

        // (3) bind height to 2 * width
        height: 2 * width

        // (4) custom property
        property int times: 24

        // (5) property alias
        property alias anotherTimes: thisLabel.times

        // (6) set text appended by value
        text: "Greetings " + times

        // (7) font is a grouped property
        font.family: "Ubuntu"
        font.pixelSize: 24

        // (8) KeyNavigation is an attached property
        KeyNavigation.tab: otherLabel

        // (9) signal handler for property changes
        onHeightChanged: console.log('height:', height)

        // focus is need to receive key events
        focus: true

        // change color based on focus value
        color: focus?"red":"black"
    }

Let’s go through the different features of properties:

  1. id is a very special property-like value, it is used to reference elements inside a QML file (called “document” in QML). The id is not a string type but rather an identifier and part of the QML syntax. An id needs to be unique inside a document and it can’t be re-set to a different value, nor may it be queried. (It behaves more like a pointer in the C++ world.)

  2. A property can be set to a value, depending on its type. If no value is given for a property, an initial value will be chosen. You need to consult the documentation of the particular element for more information about the initial value of a property.

  3. A property can depend on one or many other properties. This is called binding. A bound property is updated, when its dependent properties change. It works like a contract, in this case the height should always be two times the width.

  4. Adding own properties to an element is done using the property qualifier followed by the type, the name and the optional initial value (property <type> <name> : <value>). If no initial value is given a system initial value is chosen.

    Note

    You can also declare one property to be the default property if no property name is given by prepending the property declaration with the default keyword. This is used for example when you add child elements, the child elements are added automatically to the default property children of type list if they are visible elements.

  5. Another important way of declaring properties is using the alias keyword (property alias <name> : <reference>). The alias keyword allows us to forward a property of an object or an object itself from within the type to an outer scope. We will use this technique later when defining components to export the inner properties or element ids to the root level. A property alias does not need a type, it uses the type of the referenced property or object.

  6. The text property depends on the custom property times of type int. The int based value is automatically converted to a string type. The expression itself is another example of binding and results into the text being updated every time the times property changes.

  7. Some properties are grouped properties. This feature is used when a property is more structured and related properties should be grouped together. Another way of writing grouped properties is font { family: "Ubuntu"; pixelSize: 24 }.

  8. Some properties are attached to the element itself. This is done for global relevant elements which appear only once in the application (e.g. keyboard input). The writing is <Element>.<property>: <value>.

  9. For every property you can provide a signal handler. This handler is called after the property changes. For example here we want to be notified whenever the height changes and use the built-in console to log a message to the system.

Warning

An element id should only be used to reference elements inside your document (e.g. the current file). QML provides a mechanism called dynamic-scoping where later loaded documents overwrite the element id’s from earlier loaded documents. This makes it possible to reference element id’s from earlier loaded documents, if they are not yet overwritten. It’s like creating global variables. Unfortunately this frequently leads to really bad code in practice, where the program depends on the order of execution. Unfortunately this can’t be turned off. Please only use this with care or even better don’t use this mechanism at all. It’s better to export the element you want to provide to the outside world using properties on the root element of your document.

4.1.2. Scripting

Issues: Create | View

QML and JavaScript (also known as ECMAScript) are best friends. In the JavaScript chapter we will go into more detail on this symbiosis. Currently we just want to make you aware about this relationship.

    Text {
        id: label

        x: 24; y: 24

        // custom counter property for space presses
        property int spacePresses: 0

        text: "Space pressed: " + spacePresses + " times"

        // (1) handler for text changes
        onTextChanged: console.log("text changed to:", text)

        // need focus to receive key events
        focus: true

        // (2) handler with some JS
        Keys.onSpacePressed: {
            increment()
        }

        // clear the text on escape
        Keys.onEscapePressed: {
            label.text = ''
        }

        // (3) a JS function
        function increment() {
            spacePresses = spacePresses + 1
        }
    }
  1. The text changed handler onTextChanged prints the current text every-time the text changed due to a space-bar key pressed
  2. When the text element receives the space-bar key (because the user pressed the space-bar on the keyboard) we call a JavaScript function increment().
  3. Definition of a JavaScript function in the form of function <name>(<parameters>) { ... }, which increments our counter spacePressed. Every time spacePressed is incremented, bound properties will also be updated.

Note

The difference between the QML : (binding) and the JavaScript = (assignment) is, that the binding is a contract and keeps true over the lifetime of the binding, whereas the JavaScript assignment (=) is a one time value assignment. The lifetime of a binding ends, when a new binding is set to the property or even when a JavaScript value is assigned is to the property. For example a key handler setting the text property to an empty string would destroy our increment display:

Keys.onEscapePressed: {
    label.text = ''
}

After pressing escape, pressing the space-bar will not update the display anymore as the previous binding of the text property (text: “Space pressed: ” + spacePresses + ” times”) was destroyed.

When you have conflicting strategies to change a property as in this case (text updated by a change to a property increment via a binding and text cleared by a JavaScript assignment) then you can’t use bindings! You need to use assignment on both property change paths as the binding will be destroyed by the assignment (broken contract!).

4.2. Basic Elements

Issues: Create | View

Elements can be grouped into visual and non-visual elements. A visual element (like the Rectangle) has a geometry and normally presents an area on the screen. A non-visual element (like a Timer) provides general functionality, normally used to manipulate the visual elements.

Currently, we will focus on the fundamental visual elements, such as Item, Rectangle, Text, Image and MouseArea.

4.2.1. Item Element

Issues: Create | View

Item is the base element for all visual elements as such all other visual elements inherit from Item. It doesn’t paint anything by itself but defines all properties which are common across all visual elements:

GroupProperties
Geometryx and y to define the top-left position, width and height for the expand of the element and also the z stacking order to lift elements up or down from their natural ordering
Layout handlinganchors (left, right, top, bottom, vertical and horizontal center) to position elements relative to other elements with their margins
Key handlingattached Key and KeyNavigation properties to control key handling and the input focus property to enable key handling in the first place
Transformationscale and rotate transformation and the generic transform property list for x,y,z transformation and their transformOrigin point
Visualopacity to control transparency, visible to show/hide elements, clip to restrain paint operations to the element boundary and smooth to enhance the rendering quality
State definitionstates list property with the supported list of states and the current state property as also the transitions list property to animate state changes.

To better understand the different properties we will try to introduce them throughout this chapter in context of the element presented. Please remember these fundamental properties are available on every visual element and work the same across these elements.

Note

The Item element is often used as a container for other elements, similar to the div element in HTML.

4.2.2. Rectangle Element

Issues: Create | View

The Rectangle extends Item and adds a fill color to it. Additionally it supports borders defined by border.color and border.width. To create rounded rectangles you can use the radius property.

../../_images/rectangle2.png

Note

Valid colors values are colors from the SVG color names (see http://www.w3.org/TR/css3-color/#svg-color). You can provide colors in QML in different ways, but the most common way is an RGB string (‘#FF4444’) or as a color name (e.g. ‘white’).

Besides a fill color and a border the rectangle also supports custom gradients.

../../_images/rectangle3.png

A gradient is defined by a series of gradient stops. Each stop has a position and a color. The position marks the position on the y-axis (0 = top, 1 = bottom). The color of the GradientStop marks the color at that position.

Note

A rectangle with no width/height set will not be visible. This happens often when you have several rectangles width (height) depending on each other and something went wrong in your composition logic. So watch out!

Note

It is not possible to create an angled gradient. For this it’s better to use predefined images. One possibility would be to just rotate the rectangle with the gradient, but be aware the geometry of an rotated rectangle will not change and thus will lead to confusion as the geometry of the element is not the same as the visible area. From the authors perspective it’s really better to use designed gradient images in that case.

4.2.3. Text Element

Issues: Create | View

To display text, you can use the Text element. Its most notable property is the text property of type string. The element calculates its initial width and height based on the given text and the font used. The font can be influenced using the font property group (e.g. font.family, font.pixelSize, ...). To change the color of the text just use the color property.

    Text {
        text: "The quick brown fox"
        color: "#303030"
        font.family: "Ubuntu"
        font.pixelSize: 28
    }

../../_images/text.png

Text can be aligned to each side and the center using the horizontalAlignment and verticalAlignment properties. To further enhance the text rendering you can use the style and styleColor property , which allows you render the text in outline, raised and sunken mode. For longer text you often want to define a break position like A very ... long text, this can be achieved using the elide property. The elide property allows you to set the elide position to the left, right or middle of your text. In case you don’t want the ‘...’ of the elide mode to appear but still want to see the full text you can also wrap the text using the wrapMode property (works only when width is explicitly set):

Text {
    width: 40; height: 120
    text: 'A very long text'
    // '...' shall appear in the middle
    elide: Text.ElideMiddle
    // red sunken text styling
    style: Text.Sunken
    styleColor: '#FF4444'
    // align text to the top
    verticalAlignment: Text.AlignTop
    // only sensible when no elide mode
    // wrapMode: Text.WordWrap
}

A Text element only displays the given text. It does not render any background decoration. Besides the rendered text the Text element is transparent. It’s part of your overall design to provide a sensible background to the text element.

Note

Be aware a Text initial width (height) is depending on the text string and on the font set. A Text element with no width set and no text will not be visible, as the initial width will be 0.

Note

Often when you want to layout Text elements you need to differentiate between aligning the text inside the Text element boundary box or to align the element boundary box itself. In the former you want to use the horizontalAlignment and verticalAlignment properties and in the later case you want to manipulate the element geometry or use anchors.

4.2.4. Image Element

Issues: Create | View

An Image element is able to display images in various formats (e.g. PNG, JPG, GIF, BMP, WEBP). For the full list of supported image formats, please consult the Qt documentation. Besides the obvious source property to provide the image URL it contains a fillMode which controls the resizing behavior.

    Image {
        x: 12; y: 12
        // width: 72
        // height: 72
        source: "assets/triangle_red.png"
    }
    Image {
        x: 12+64+12; y: 12
        // width: 72
        height: 72/2
        source: "assets/triangle_red.png"
        fillMode: Image.PreserveAspectCrop
        clip: true
    }
../../_images/image.png

Note

A URL can be a local path with forward slashes ( ”./images/home.png” ) or a web-link (e.g. “http://example.org/home.png”).

Note

Image elements using PreserveAspectCrop should also enable the clipping to avoid image data being rendered outside the Image boundaries. By default clipping is disabled (clip : false). You need to enable clipping (clip : true) to constrain the painting to the elements bounding rectangle. This can be used on any visual element.

Tip

Using C++ you are able to create your own image provider using QQmlImageProvider. This allows you to create images on the fly and threaded image loading.

4.2.5. MouseArea Element

Issues: Create | View

To interact with these elements you often will use a MouseArea. It’s a rectangular invisible item in where you can capture mouse events. The mouse area is often used together with a visible item to execute commands when the user interacts with the visual part.

    Rectangle {
        id: rect1
        x: 12; y: 12
        width: 76; height: 96
        color: "lightsteelblue"
        MouseArea {
            id: area
            width: parent.width
            height: parent.height
            onClicked: rect2.visible = !rect2.visible
        }
    }

    Rectangle {
        id: rect2
        x: 112; y: 12
        width: 76; height: 96
        border.color: "lightsteelblue"
        border.width: 4
        radius: 8
    }
../../_images/mousearea1.png
../../_images/mousearea2.png

Note

This is an important aspect of Qt Quick, the input handling is separated from the visual presentation. By this it allows you to show the user an interface element, but the interaction area can be larger.

4.3. Components

Issues: Create | View

A component is a reusable element and QML provides different ways to create components. Currently we will look only at the simplest form - a file based component. A file based component is created by placing a QML element in a file and give the file an element name (e.g. Button.qml). You can use the component like every other element from the QtQuick module, in our case you would use this in your code as Button { ... }.

For example, let’s create a rectangle containing a text componenet and a mouse area. This resembles a simple button and doesn’t need to be more complicated for our purposes.

The UI will look similar to this. On the left the UI in the initial state, on the right after the button has been clicked.

../../_images/button_waiting.png
../../_images/button_clicked.png

Our task is now to extract the button UI in a reusable component. For this we shortly think about a possible API for our button. You can do this by imagining how someone else should use your button. Here’s what I came up with:

// minimal API for a button
Button {
    text: "Click Me"
    onClicked: { // do something }
}

I would like to set the text using a text property and to implement my own click handler. Also I would expect the button to have a sensible initial size, which I can overwrite (e.g. with width: 240 for example).

To achieve this we create a Button.qml file and copy our button UI inside. Additionally we need to export the properties a user might want to change on the root level.

// Button.qml

import QtQuick 2.5

Rectangle {
    id: root
    // export button properties
    property alias text: label.text
    signal clicked

    width: 116; height: 26
    color: "lightsteelblue"
    border.color: "slategrey"

    Text {
        id: label
        anchors.centerIn: parent
        text: "Start"
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            root.clicked()
        }
    }
}

We have exported the text and clicked signal on the root level. Typically we name our root element root to make the referencing easier. We use the alias feature of QML, which is a way to export properties inside nested QML elements to the root level and make this available for the outside world. It is important to know, that only the root level properties can be accessed from outside this file by other components.

To use our new Button element we can simply declare it in our file. So the earlier example will become a little bit simplified.

    Button { // our Button component
        id: button
        x: 12; y: 12
        text: "Start"
        onClicked: {
            status.text = "Button clicked!"
        }
    }

    Text { // text changes when button was clicked
        id: status
        x: 12; y: 76
        width: 116; height: 26
        text: "waiting ..."
        horizontalAlignment: Text.AlignHCenter
    }

Now you can use as many buttons as you like in your UI by just using Button { ... }. A real button could be more complex, e.g providing feedback when clicked or showing a nicer decoration.

Note

Personally you could even go a step further and use an item as a root element. This prevents users to change the color of our designed button, and provides us more control about the exported API. The target should be to export a minimal API. Practically this means we would need to replace the root Rectangle with an Item and make the rectangle a nested element in the root item.


Item {
    id: root
    width: 116; height: 26

    property alias text: label.text
    signal clicked

    Rectangle {
        anchors.fill parent
        color: "lightsteelblue"
        border.color: "slategrey"
    }
    ...
}

With this technique, it is easy to create a whole series of reusable components.

4.4. Simple Transformations

Issues: Create | View

A transformation manipulates the geometry of an object. QML Items can in general be translated, rotated and scaled. There is a simple form of these operations and a more advanced way.

Let’s start with the simple transformations. Here is our scene as our starting point.

A simple translation is done via changing the x,y position. A rotation is done using the rotation property. The value is provided in degrees (0 .. 360). A scaling is done using the scale property and a value <1 means the element is scaled down and >1 means the element is scaled up. The rotation and scaling does not change your geometry. The items x,y and width/height haven’t changed. Just the painting instructions are transformed.

Before we show off the example I would like to introduce a little helper: The ClickableImage element. The ClickableImage is just an image with a mouse area. This brings up a useful rule of thumb - if you have copied a chunk of code three times, extract it into a component.

// ClickableImage.qml

// Simple image which can be clicked

import QtQuick 2.5

Image {
    id: root
    signal clicked

    MouseArea {
        anchors.fill: parent
        onClicked: root.clicked()
    }
}
../../_images/objects.png

We use our clickable image to present three objects (box, circle, triangle). Each object performs a simple transformation when clicked. Clicking the background will reset the scene.

// transformation.qml


import QtQuick 2.5

Item {
    // set width based on given background
    width: bg.width
    height: bg.height

    Image { // nice background image
        id: bg
        source: "assets/background.png"
    }

    MouseArea {
        id: backgroundClicker
        // needs to be before the images as order matters
        // otherwise this mousearea would be before the other elements
        // and consume the mouse events
        anchors.fill: parent
        onClicked: {
            // reset our little scene
            circle.x = 84
            box.rotation = 0
            triangle.rotation = 0
            triangle.scale = 1.0
        }
    }

    ClickableImage {
        id: circle
        x: 84; y: 68
        source: "assets/circle_blue.png"
        antialiasing: true
        onClicked: {
            // increase the x-position on click
            x += 20
        }
    }

    ClickableImage {
        id: box
        x: 164; y: 68
        source: "assets/box_green.png"
        antialiasing: true
        onClicked: {
            // increase the rotation on click
            rotation += 15
        }
    }

    ClickableImage {
        id: triangle
        x: 248; y: 68
        source: "assets/triangle_red.png"
        antialiasing: true
        onClicked: {
            // several transformations
            rotation += 15
            scale += 0.05
        }
    }

    function _test_transformed() {
        circle.x += 20
        box.rotation = 15
        triangle.scale = 1.2
        triangle.rotation = -15
    }

    function _test_overlap() {
        circle.x += 40
        box.rotation = 15
        triangle.scale = 2.0
        triangle.rotation = 45
    }

}
../../_images/objects_transformed.png

The circle increments the x-position on each click and the box will rotate on each click. The triangle will rotate and scale the image down on each click, to demonstrate a combined transformation. For the scaling and rotation operation we set antialiasing: true to enable anti-aliasing, which is switched off (same as the clipping property clip) for performance reasons. In your own work, when you see some rasterized edges in your graphics, then you should probably switch smooth on.

Note

To achieve better visual quality when scaling images it is recommended to scale images down instead of up. Scaling an image up with a larger scaling factor will result into scaling artifacts (blurred image). When scaling an image you should consider using antialiasing : true to enable the usage of a higher quality filter.

The background MouseArea covers the whole background and resets the object values.

Note

Elements which appear earlier in the code have a lower stacking order (called z-order). If you click long enough on circle you will see it moves below box. The z-order can also be manipulated by the z-property of an Item.

../../_images/objects_overlap.png

This is because box appears later in the code. The same applies also to mouse areas. A mouse area later in the code will overlap (and thus grab the mouse events) of a mouse area earlier in the code.

Please remember: The order of elements in the document matters.

4.5. Positioning Elements

Issues: Create | View

There are a number of QML elements used to position items. These are called positioners and the following are provided in the QtQuick module Row, Column, Grid and Flow. They can be seen showing the same contents in the illustration below.

Note

Before we go into details, let me introduce some helper elements. The red, blue, green, lighter and darker squares. Each of these components contains a 48x48 pixels colorized rectangle. As reference here is the source code for the RedSquare:

// RedSquare.qml

import QtQuick 2.5

Rectangle {
    width: 48
    height: 48
    color: "#ea7025"
    border.color: Qt.lighter(color)
}

Please note the use of Qt.lighter(color) to produce a lighter border color based on the fill color. We will use these helpers in the next examples to make the source code more compact and hopefully readable. Please remember, each rectangle is initial 48x48 pixels.

The Column element arranges child items into a column by stacking them on top of each other. The spacing property can be used to distance each of the child elements from each other.

../../_images/column.png
// column.qml

import QtQuick 2.5

DarkSquare {
    id: root
    width: 120
    height: 240

    Column {
        id: row
        anchors.centerIn: parent
        spacing: 8
        RedSquare { }
        GreenSquare { width: 96 }
        BlueSquare { }
    }
}

// M1<<

The Row element places its child items next to each other, either from the left to the right, or from the right to the left, depending on the layoutDirection property. Again, spacing is used to separate child items.

../../_images/row.png
// row.qml

import QtQuick 2.5

BrightSquare {
    id: root
    width: 400; height: 120

    Row {
        id: row
        anchors.centerIn: parent
        spacing: 20
        BlueSquare { }
        GreenSquare { }
        RedSquare { }
    }
}

The Grid element arranges its children in a grid, by setting the rows and columns properties, the number or rows or columns can be constrained. By not setting either of them, the other is calculated from the number of child items. For instance, setting rows to 3 and adding 6 child items will result in 2 columns. The properties flow and layoutDirection are used to control the order in which the items are added to the grid, while spacing controls the amount of space separating the child items.

../../_images/grid.png
// grid.qml

import QtQuick 2.5

BrightSquare {
    id: root
    width: 160
    height: 160

    Grid {
        id: grid
        rows: 2
        columns: 2
        anchors.centerIn: parent
        spacing: 8
        RedSquare { }
        RedSquare { }
        RedSquare { }
        RedSquare { }
    }

}

The final positioner is Flow. It adds its child items in a flow. The direction of the flow is controlled using flow and layoutDirection. It can run sideways or from the top to the bottom. It can also run from left to right or in the opposite direction. As the items are added in the flow, they are wrapped to form new rows or columns as needed. In order for a flow to work, it must have a width or a height. This can be set either directly, or though anchor layouts.

../../_images/flow.png
// flow.qml

import QtQuick 2.5

BrightSquare {
    id: root
    width: 160
    height: 160

    Flow {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 20
        RedSquare { }
        BlueSquare { }
        GreenSquare { }
    }
}

An element often used with positioners is the Repeater. It works like a for-loop and iterates over a model. In the simplest case a model is just a value providing the amount of loops.

../../_images/repeater.png
// repeater.qml

import QtQuick 2.5

DarkSquare {
    id: root
    width: 252
    height: 252
    property variant colorArray: ["#00bde3", "#67c111", "#ea7025"]


    Grid{
        anchors.fill: parent
        anchors.margins: 8
        spacing: 4
        Repeater {
            model: 16
            Rectangle {
                width: 56; height: 56
                property int colorIndex: Math.floor(Math.random()*3)
                color: root.colorArray[colorIndex]
                border.color: Qt.lighter(color)
                Text {
                    anchors.centerIn: parent
                    color: "#f0f0f0"
                    text: "Cell " + index
                }
            }
        }
    }
}

In this repeater example, we use some new magic. We define our own color property, which we use as an array of colors. The repeater creates a series of rectangles (16, as defined by the model). For each loop he creates the rectangle as defined by the child of the repeater. In the rectangle we chose the color by using JS math functions Math.floor(Math.random()*3). This gives us a random number in the range from 0..2, which we use to select the color from our color array. As noted earlier, JavaScript is a core part of Qt Quick, as such the standard libraries are available for us.

A repeater injects the index property into the repeater. It contains the current loop-index. (0,1,..15). We can use this to make our own decisions based on the index, or in our case to visualize the current index with the Text element.

Note

More advanced handling of larger models and kinetic views with dynamic delegates is covered in an own model-view chapter. Repeaters are best used when having a small amount of static data to be presented.

4.6. Layout Items

Issues: Create | View

Todo

do we need to remove all uses of anchors earlier?

QML provides a flexible way to layout items using anchors. The concept of anchoring is part of the Item fundamental properties and available to all visual QML elements. An anchors acts like a contract and is stronger than competing geometry changes. Anchors are expressions of relativeness, you always need a related element to anchor with.

../../_images/anchors.png

An element has 6 major anchor lines (top, bottom, left, right, horizontalCenter, verticalCenter). Additional there is the baseline anchor for text in Text elements. Each anchor line comes with an offset. In the case of top, bottom, left and right they are called margins. For horizontalCenter, verticalCenter and baseline they are called offsets.

../../_images/anchorgrid.png
  1. An element fills a parent element

            GreenSquare {
                BlueSquare {
                    width: 12
                    anchors.fill: parent
                    anchors.margins: 8
                    text: '(1)'
                }
            }
    
  2. An element is left aligned to the parent

            GreenSquare {
                BlueSquare {
                    width: 48
                    y: 8
                    anchors.left: parent.left
                    anchors.leftMargin: 8
                    text: '(2)'
                }
            }
    
  3. An element left side is aligned to the parents right side

            GreenSquare {
                BlueSquare {
                    width: 48
                    anchors.left: parent.right
                    text: '(3)'
                }
            }
    
  4. Center aligned elements. Blue1 is horizontal centered on the parent. Blue2 is also horizontal centered but on Blue1 and it’s top is aligned to the Blue1 bottom line.

            GreenSquare {
                BlueSquare {
                    id: blue1
                    width: 48; height: 24
                    y: 8
                    anchors.horizontalCenter: parent.horizontalCenter
                }
                BlueSquare {
                    id: blue2
                    width: 72; height: 24
                    anchors.top: blue1.bottom
                    anchors.topMargin: 4
                    anchors.horizontalCenter: blue1.horizontalCenter
                    text: '(4)'
                }
            }
    
  5. An element is centered on a parent element

            GreenSquare {
                BlueSquare {
                    width: 48
                    anchors.centerIn: parent
                    text: '(5)'
                }
            }
    
  6. An element is centered with an left-offset on a parent element using horizontal and vertical center lines

            GreenSquare {
                BlueSquare {
                    width: 48
                    anchors.horizontalCenter: parent.horizontalCenter
                    anchors.horizontalCenterOffset: -12
                    anchors.verticalCenter: parent.verticalCenter
                    text: '(6)'
                }
            }
    

Note

Our squares have been enhanced to enable dragging. Try the example and drag around some squares. You will see that (1) can’t be dragged as it’s anchored on all sides, sure you can drag the parent of (1) as it’s not anchored at all. (2) can be vertically dragged as only the left side is anchored. Similar applies to (3). (4) can only be dragged vertically as both squares are horizontal centered. (5) is centered on the parent and as such can’t be dragged, similar applies to (7). Dragging an element means changing their x,y position. As anchoring is stronger than geometry changes such as x,y, dragging is restricted by the anchored lines. We will see this effect later when we discuss animations.

4.7. Input Elements

Issues: Create | View

We have already used the MouseArea as a mouse input element. Next, we’ll focus on keyboard input. We start off with the text editing elements: TextInput and TextEdit.

4.7.1. TextInput

Issues: Create | View

The TextInput allows the user to enter a line of text. The element supports input constraints such as validator, inputMask, and echoMode.

// textinput.qml

import QtQuick 2.5

Rectangle {
    width: 200
    height: 80
    color: "linen"

    TextInput {
        id: input1
        x: 8; y: 8
        width: 96; height: 20
        focus: true
        text: "Text Input 1"
    }

    TextInput {
        id: input2
        x: 8; y: 36
        width: 96; height: 20
        text: "Text Input 2"
    }
}
../../_images/textinput.png

The user can click inside a TextInput to change the focus. To support switching the focus by keyboard, we can use the KeyNavigation attached property.

// textinput2.qml

import QtQuick 2.5

Rectangle {
    width: 200
    height: 80
    color: "linen"

    TextInput {
        id: input1
        x: 8; y: 8
        width: 96; height: 20
        focus: true
        text: "Text Input 1"
        KeyNavigation.tab: input2
    }

    TextInput {
        id: input2
        x: 8; y: 36
        width: 96; height: 20
        text: "Text Input 2"
        KeyNavigation.tab: input1
    }
}

The KeyNavigation attached property supports a preset of navigation keys where an element id is bound to switch focus on the given key press.

A text input element comes with no visual presentation besides a blinking cursor and the entered text. For the user to be able to recognize the element as an input element it needs some visual decoration, for example a simple rectangle. When placing the TextInput inside an element you need make sure you export the major properties you want others be able to access.

We move this piece of code into our own component called TLineEditV1 for reuse.

// TLineEditV1.qml

import QtQuick 2.5

Rectangle {
    width: 96; height: input.height + 8
    color: "lightsteelblue"
    border.color: "gray"

    property alias text: input.text
    property alias input: input

    TextInput {
        id: input
        anchors.fill: parent
        anchors.margins: 4
        focus: true
    }
}

Note

If you want to export the TextInput completely, you can export the element by using property alias input: input. The first input is the property name, where the 2nd input is the element id.

We rewrite our KeyNavigation example with the new TLineEditV1 component.

Rectangle {
    ...
    TLineEditV1 {
        id: input1
        ...
    }
    TLineEditV1 {
        id: input2
        ...
    }
}
../../_images/textinput3.png

And try the tab key for navigation. You will experience the focus does not change to input2. The simple use of focus:true is not sufficient. The problem arises, that the focus was transferred to the input2 element the top-level item inside the TlineEditV1 (our Rectangle) received focus and did not forward the focus to the TextInput. To prevent this QML offers the FocusScope.

4.7.2. FocusScope

Issues: Create | View

A focus scope declares that the last child element with focus:true receives the focus if the focus scope receives the focus. So it’s forward the focus to the last focus requesting child element. We will create a 2nd version of our TLineEdit component called TLineEditV2 using the focus scope as root element.

// TLineEditV2.qml

import QtQuick 2.5

FocusScope {
    width: 96; height: input.height + 8
    Rectangle {
        anchors.fill: parent
        color: "lightsteelblue"
        border.color: "gray"

    }

    property alias text: input.text
    property alias input: input

    TextInput {
        id: input
        anchors.fill: parent
        anchors.margins: 4
        focus: true
    }
}

Our example will now look like this:

Rectangle {
    ...
    TLineEditV2 {
        id: input1
        ...
    }
    TLineEditV2 {
        id: input2
        ...
    }
}

Pressing the tab key now successfully switches the focus between the 2 components and the correct child element inside the component is focused.

4.7.3. TextEdit

Issues: Create | View

The TextEdit is very similar to TextInput and support a multi-line text edit field. It doesn’t have the text constraint properties as this depends on querying the painted size of the text (paintedHeight, paintedWidth). We also create our own component called TTextEdit to provide a edit background and use the focus scope for better focus forwarding.

// TTextEdit.qml

import QtQuick 2.5

FocusScope {
    width: 96; height: 96
    Rectangle {
        anchors.fill: parent
        color: "lightsteelblue"
        border.color: "gray"

    }

    property alias text: input.text
    property alias input: input

    TextEdit {
        id: input
        anchors.fill: parent
        anchors.margins: 4
        focus: true
    }
}

You can use it like the TLineEdit component

// textedit.qml

import QtQuick 2.5

Rectangle {
    width: 136
    height: 120
    color: "linen"

    TTextEdit {
        id: input
        x: 8; y: 8
        width: 120; height: 104
        focus: true
        text: "Text Edit"
    }
}
../../_images/textedit.png

4.7.4. Keys Element

Issues: Create | View

The attached property Keys allows executing code based on certain key presses. For example to move a square around and scale we can hook into the up, down, left and right keys to translate the element and the plus, minus key to scale the element.

// keys.qml

import QtQuick 2.5

DarkSquare {
    width: 400; height: 200

    GreenSquare {
        id: square
        x: 8; y: 8
    }
    focus: true
    Keys.onLeftPressed: square.x -= 8
    Keys.onRightPressed: square.x += 8
    Keys.onUpPressed: square.y -= 8
    Keys.onDownPressed: square.y += 8
    Keys.onPressed: {
        switch(event.key) {
            case Qt.Key_Plus:
                square.scale += 0.2
                break;
            case Qt.Key_Minus:
                square.scale -= 0.2
                break;
        }

    }
}
../../_images/keys.png
【电力系统】单机无穷大电力系统短路故障暂态稳定Simulink仿真(带说明文档)内容概要:本文档围绕“单机无穷大电力系统短路故障暂态稳定Simulink仿真”展开,提供了完整的仿真模型与说明文档,重点研究电力系统在发生短路故障后的暂态稳定性问题。通过Simulink搭建单机无穷大系统模型,模拟不同类型的短路故障(如三相短路),分析系统在故障期间及切除后的动态响应,包括发电机转子角度、转速、电压和功率等关键参数的变化,进而评估系统的暂态稳定能力。该仿真有助于理解电力系统稳定性机理,掌握暂态过程分析方法。; 适合人群:电气工程及相关专业的本科生、研究生,以及从事电力系统分析、运行与控制工作的科研人员和工程师。; 使用场景及目标:①学习电力系统暂态稳定的基本概念与分析方法;②掌握利用Simulink进行电力系统建模与仿真的技能;③研究短路故障对系统稳定性的影响及提高稳定性的措施(如故障清除时间优化);④辅助课程设计、毕业设计或科研项目中的系统仿真验证。; 阅读建议:建议结合电力系统稳定性理论知识进行学习,先理解仿真模型各模块的功能与参数设置,再运行仿真并仔细分析输出结果,尝试改变故障类型或系统参数以观察其对稳定性的影响,从而深化对暂态稳定问题的理解。
本研究聚焦于运用MATLAB平台,将支持向量机(SVM)应用于数据预测任务,并引入粒子群优化(PSO)算法对模型的关键参数进行自动调优。该研究属于机器学习领域的典型实践,其核心在于利用SVM构建分类模型,同时借助PSO的全局搜索能力,高效确定SVM的最优超参数配置,从而显著增强模型的整体预测效能。 支持向量机作为一种经典的监督学习方法,其基本原理是通过在高维特征空间中构造一个具有最大间隔的决策边界,以实现对样本数据的分类或回归分析。该算法擅长处理小规模样本集、非线性关系以及高维度特征识别问题,其有效性源于通过核函数将原始数据映射至更高维的空间,使得原本复杂的分类问题变得线性可分。 粒子群优化算法是一种模拟鸟群社会行为的群体智能优化技术。在该算法框架下,每个潜在解被视作一个“粒子”,粒子群在解空间中协同搜索,通过不断迭代更新自身速度与位置,并参考个体历史最优解和群体全局最优解的信息,逐步逼近问题的最优解。在本应用中,PSO被专门用于搜寻SVM中影响模型性能的两个关键参数——正则化参数C与核函数参数γ的最优组合。 项目所提供的实现代码涵盖了从数据加载、预处理(如标准化处理)、基础SVM模型构建到PSO优化流程的完整步骤。优化过程会针对不同的核函数(例如线性核、多项式核及径向基函数核等)进行参数寻优,并系统评估优化前后模型性能的差异。性能对比通常基于准确率、精确率、召回率及F1分数等多项分类指标展开,从而定量验证PSO算法在提升SVM模型分类能力方面的实际效果。 本研究通过一个具体的MATLAB实现案例,旨在演示如何将全局优化算法与机器学习模型相结合,以解决模型参数选择这一关键问题。通过此实践,研究者不仅能够深入理解SVM的工作原理,还能掌握利用智能优化技术提升模型泛化性能的有效方法,这对于机器学习在实际问题中的应用具有重要的参考价值。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
<think>好的,用户想了解MongoDB Stitch的功能和用法。首先,我需要回忆一下MongoDB Stitch是什么。根据之前的引用,Stitch是MongoDB提供的后端即服务(BaaS),帮助开发者快速构建应用而无需管理底层基础设施。用户可能需要知道它的核心功能、如何集成以及使用场景。 首先,查看引用中的资料。引用[3]提到Stitch JavaScript SDK用于在JavaScript应用中集成,可能需要介绍SDK的使用方法。引用[4]提到整合MongoDB和Amazon Kinesis,可能涉及数据流的处理,这可以作为应用场景的例子。引用[1]和[2]提供了MongoDB的基本概念和文档资源,需要确保回答中的术语准确,并引导用户查阅官方文档。 接下来,组织回答结构。用户要求功能和用法指南,应该分点说明核心功能,比如数据访问控制、服务集成、无服务器函数、触发器、身份验证等。然后分步骤说明使用指南,包括环境准备、数据建模、配置规则、编写函数、集成外部服务等。每个部分需要结合引用内容,例如在说明数据访问控制时引用[3]的SDK部分,在服务集成时提到引用[4]的Kinesis整合。 需要确保使用正确的LaTeX格式,比如内联变量用$...$,但可能在这个回答中涉及较少数学公式,更多是技术术语。如果有代码示例,需要用代码块,但用户没有具体请求代码,可能不需要。不过,可以提到SDK的使用,如引用[3]中的JavaScript SDK。 可能还需要生成相关问题,比如如何配置触发器,如何与AWS服务集成,身份验证机制有哪些,适合移动应用开发吗,以及性能优化方法。这些问题应基于回答内容中的关键点,引导用户进一步探索。 最后,检查引用标注是否正确,每个引用来源是否在末尾正确对应,比如引用[3]和[4]在相关部分末尾添加标识。确保回答结构清晰,分点明确,语言简洁,符合用户要求的中文回答。</think>### MongoDB Stitch 功能与使用指南 #### 一、核心功能 1. **无服务器后端服务** MongoDB Stitch 提供后端即服务(BaaS),开发者无需管理服务器即可处理数据存储、用户认证等任务。例如,通过 Stitch 可直接访问 MongoDB 数据库,并集成第三方服务(如 AWS Kinesis)实现数据流处理[^4]。 2. **数据访问控制** 支持细粒度权限管理,通过规则(Rules)定义集合或字段级别的访问权限。例如: ```json { "roles": [{"name": "readOnly", "apply_when": {}, "read": true}] } ``` 3. **服务集成** 可无缝集成外部服务(如 AWS、Twilio、HTTP APIs),通过 Stitch 的 `Services` 功能调用 API。例如,将 MongoDB 数据实时同步到 Amazon Kinesis 进行流分析。 4. **无服务器函数(Functions)** 支持 JavaScript 编写函数,直接在 Stitch 界面部署,用于处理业务逻辑或数据转换。例如: ```javascript exports = function(data) { return context.services.get("mongodb").db("mydb").collection("users").insertOne(data); }; ``` 5. **实时触发器(Triggers)** 基于数据库变更(如插入、更新)触发自定义操作。例如,当新文档插入集合时,自动发送通知或更新关联数据[^3]。 #### 二、使用指南 1. **环境准备** - 在 MongoDB Atlas 控制台启用 Stitch 服务。 - 安装 Stitch CLI 或使用 Stitch JavaScript SDK[^3]。 2. **数据建模与访问规则** - 在 Atlas 中创建数据库和集合。 - 通过 `Rules` 配置访问权限(如仅允许认证用户读写特定字段)。 3. **配置服务集成** - 在 `Services` 中添加第三方服务(如 AWS),配置 API 密钥或 OAuth。 - 通过 `HTTP Service` 调用外部 REST API。 4. **编写无服务器函数** - 在 `Functions` 中创建 JavaScript 函数,使用 `context` 对象调用数据库或服务: $$ \text{示例:context.services.get("aws-s3").uploadFile(bucket, key, data)} $$ 5. **设置实时触发器** - 在 `Triggers` 中定义触发器类型(如 Database Trigger),关联集合和触发条件。 - 绑定到指定函数实现自动化流程。 #### 三、典型应用场景 1. **移动应用后端** 快速实现用户注册、数据存储及推送通知,无需自建服务器[^3]。 2. **物联网(IoT)数据流处理** 结合 Amazon Kinesis 处理设备实时数据,存储至 MongoDB 并触发分析任务。 3. **微服务架构** 通过 Stitch Functions 封装业务逻辑,降低服务间耦合度。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值