Qt Declarative Online Coding App

BETA - Demo App*

With zero installation, test out what it is like to prototype, modify and create user interfaces using a CSS and JavaScript like declarative programming language, Qt QML. It is designed for productivity and easy UI development of cross-platform C++ and Python Qt applications.

This interactive WebAssembly based app includes multiple examples of typical scripting syntax and coding which you can run in this online editor. Click and load the examples below!

Check out the other features and functionality that comprise the Qt framework and development tools.

import QtQuick 2.3 Rectangle { width: 200 height: 100 color: "#41cd52" Text { anchors.centerIn: parent text: "Hello, World!" color: "#fff" } }

Click and Load Examples

These examples will demo the simplicity of creating fluid user experiences and the ease of coding designs for 2D and 3D (not yet supported in this beta) UIs with just a few lines of Qt QML code. You can run the examples with one simple click. 

  • Smarthome control panel

    Look at how easily you can create icon-based menus with any shape. Modify the path properties to blur and scale icons or change the path control points to modify the path shape.

    Load this example
    /****************************************************************************
    **
    ** Copyright (C) 2020 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.14
    import QtQuick.Window 2.2
    
    Window {
        id: rootWindow
    
        title: qsTr("Smart home")
        width: 640; height: 400
        visible: true
        color: "white"
    
        // The background consists of two active buttons to switch the ViewSection
        // between a grid and path view.
        Image {
            id: background
            width: 640
            height: 400
            source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/smartHome/qt-demo-screen-white.png"
    
            // Button Qt Quick Control could be used instead of Image. There is another Qt Quick Control example.
            Image {
                id: gridButtonImage
                source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/smartHome/interface.png"
                width: 20 // We want to have a fixed size for the image
                height: width
                anchors { top: background.top; left: background.left; topMargin: 12; leftMargin: 50 }
                TapHandler {
                    onTapped: pathView.visible = false;
                }
            }
    
            Image {
                source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/smartHome/balls.png"
                width: gridButtonImage.width
                height: width
                anchors { top: background.top; left: background.left; topMargin: 12; leftMargin: 85 }
                TapHandler {
                    onTapped: pathView.visible = true;
                }
            }
        }
    
        // ListModel provides images, shared between the grid and path views.
        ListModel {
            id: imageModel
            ListElement {
                file: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/smartHome/door.png"
            }
            ListElement {
                file: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/smartHome/home.png"
            }
            ListElement {
                file: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/smartHome/power.png"
            }
            ListElement {
                file: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/smartHome/signs.png"
            }
            ListElement {
                file: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/smartHome/tool.png"
            }
            ListElement {
                file: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/smartHome/weapons.png"
            }
        }
    
        // Delegate is used by the views to render the model items
        Component {
            id: pathViewDelegate
            Image {
                opacity: PathView.opacity
                scale: PathView.scale
                z: PathView.z
                source: file
                width: 64
                height: 64
                fillMode: Image.PreserveAspectFit
            }
        }
    
        Component {
            id: gridViewDelegate
            Image {
                source: file
                width: 64
                height: 64
                fillMode: Image.PreserveAspectFit
                TapHandler {
                    onLongPressed: scale = (scale === 1.5) ? 1.0 : 1.5;
                }
                Behavior on scale {
                    NumberAnimation { }
                }
            }
        }
    
        Component {
            id: hightlightRectangle
            Rectangle {
                radius: 4
                color: "transparent"
                border { width: 2; color: "lightgreen" }
                width: 64 + 4
                height: width
                visible: PathView.onPath
            }
        }
    
        GridView {
            id: gridView
            visible: !pathView.visible
            anchors.centerIn: parent
            width: parent.width * 0.5
            height: parent.height * 0.5
            model: imageModel
            delegate: gridViewDelegate
        }
    
        PathView {
            id: pathView
            anchors.centerIn: parent
            width: parent.width * 0.8
            height: parent.height * 0.8
            model: imageModel
            delegate: pathViewDelegate
            visible: true
            highlight: hightlightRectangle
            path: Path {
                startX: 208; startY: 265
                PathAttribute { name: "opacity"; value: 1.0 }
                PathAttribute { name: "scale"; value: 1.0 }
                PathAttribute { name: "z"; value: 0 }
                PathCubic { x: 37; y: 142; control1X: 139; control1Y: 250
                    control2X: 53; control2Y: 237 }
                PathAttribute { name: "opacity"; value: 0.5 }
                PathAttribute { name: "scale"; value: 0.5 }
                PathAttribute { name: "z"; value: -1 }
                PathCubic { x: 94; y: 59; control1X: 41.1; control1Y: 117.1
                    control2X: 60.9; control2Y: 77.9 }
                PathAttribute { name: "opacity"; value: 0.25 }
                PathAttribute { name: "scale"; value: 0.25 }
                PathAttribute { name: "z"; value: -2 }
                PathCubic { x: 364; y: 56; control1X: 161.9; control1Y: 32.6
                    control2X: 274.1; control2Y: 25.4 }
                PathAttribute { name: "opacity"; value: 0.5 }
                PathAttribute { name: "scale"; value: 0.5 }
                PathAttribute { name: "z"; value: -1 }
                PathCubic { x: 208; y: 265; control1X: 478.4; control1Y: 152.3
                    control2X: 409.6; control2Y: 277.7 }
            }
        }
    }
    
  • Smooth Animations

    QML provides developers with a variety of animation types, which makes it possible to write fluid animations with just a few lines of code.

    Load this example
    /****************************************************************************
    **
    ** Copyright (C) 2020 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.14
    import QtQuick.Window 2.2
    
    Window {
        title: qsTr("SmoothAnimations")
        id: window
        width: 640
        height: 480
        visible: true
    
        // Background
        Image {
            x: 0
            y: 0
            width: parent.width
            height: parent.height
            source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/animations/rocketpath.png"
        }
    
        AnimatedSprite {
            id: animatedSprite
            width: parent.width * 0.1
            height: parent.height * 0.1
            anchors { top: parent.top; topMargin: 20; right: parent.right; rightMargin: 20 }
            source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/animations/snowflake.png"
            frameCount: 51  // Frame width automatically calculated
            frameDuration: 10
            running: false
            TapHandler {
                onTapped: animatedSprite.running = !animatedSprite.running;
            }
        }
    
        Item {
            id: rocket
            width: 128; height: 96
            Image {
                source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/animations/rocket.png"
                anchors.centerIn: parent
                rotation: 90
            }
            TapHandler {
                onTapped: pathAnimation.running = !pathAnimation.running
            }
        }
    
        PathAnimation {
            id: pathAnimation
            duration: 2000
            easing.type: Easing.InOutQuad
            loops: 1
            target: rocket
            orientation: PathAnimation.RightFirst
            anchorPoint: Qt.point(rocket.width/2, rocket.height/2)
            path: Path {
                startX: rocket.width/2; startY: rocket.height/2
                PathCubic {
                    x: window.width - rocket.width/2
                    y: window.height - rocket.height/2
                    control1X: x; control1Y: rocket.height/2
                    control2X: rocket.width/2; control2Y: y
                }
                PathCubic {
                    x: window.width - rocket.width/2
                    y: window.height - rocket.height/2
                    control1X: x; control1Y: rocket.height/2
                    control2X: rocket.width/2; control2Y: y
                }
            }
        }
    
        Image {
            id: img
            source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/animations/face-smile.png"
            anchors.horizontalCenter: parent.horizontalCenter
            TapHandler {
                onTapped: bounceAnimation.running = !bounceAnimation.running
            }
            SequentialAnimation on y {
                id: bounceAnimation
                running: false
                loops: 1
                YAnimator {
                    easing.amplitude: 1.6
                    to: window.height-img.height; easing.type: Easing.InOutElastic; duration: 2000
                }
                PauseAnimation { duration: 1000 }
                YAnimator {
                    to: 0; easing.type: Easing.OutQuad; duration: 1000
                }
            }
        }
    }
    
  • Qt Quick Controls Gallery

    Qt Quick Controls are the essential building blocks of the user interface. See, how easy it is to create and customise the controls for your UI needs.

    Load this example
    /****************************************************************************
    **
    ** Copyright (C) 2020 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.14
    import QtQuick.Layouts 1.14
    import QtQuick.Controls 2.14
    import QtQuick.Controls.Material 2.14
    import QtQuick.Controls.Universal 2.14
    
    ApplicationWindow {
        id: window
        width: 360
        height: 520
        visible: true
        title: "Qt Quick Controls Gallery"
    
        Shortcut {
            sequences: ["Esc", "Back"]
            enabled: stackView.depth > 1
            onActivated: navigateBackAction.trigger()
        }
        Action {
            id: navigateBackAction
            icon.source: stackView.depth > 1 ? "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/QQC/back.png" : "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/QQC/drawer.png"
            onTriggered: {
                if (stackView.depth > 1) {
                    stackView.pop()
                    listView.currentIndex = -1
                } else {
                    drawer.open()
                }
            }
        }
        Shortcut {
            sequence: "Menu"
            onActivated: optionsMenuAction.trigger()
        }
        Action {
            id: optionsMenuAction
            icon.source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/QQC/menu.png"
            onTriggered: optionsMenu.open()
        }
    
        header: ToolBar {
            Material.foreground: "white"
    
            RowLayout {
                spacing: 20
                anchors.fill: parent
                ToolButton {
                    action: navigateBackAction
                }
                Label {
                    id: titleLabel
                    text: listView.currentItem ? listView.currentItem.text : "Gallery"
                    font.pixelSize: 20
                    elide: Label.ElideRight
                    horizontalAlignment: Qt.AlignHCenter
                    verticalAlignment: Qt.AlignVCenter
                    Layout.fillWidth: true
                }
                ToolButton {
                    action: optionsMenuAction
                    Menu {
                        id: optionsMenu
                        x: parent.width - width
                        transformOrigin: Menu.TopRight
                        Action {
                            text: "About"
                            onTriggered: aboutDialog.open()
                        }
                    }
                }
            }
        }
    
        Drawer {
            id: drawer
            width: Math.min(window.width, window.height) / 3 * 2
            height: window.height
            interactive: stackView.depth === 1
    
            ListView {
                id: listView
    
                focus: true
                currentIndex: -1
                anchors.fill: parent
                delegate: ItemDelegate {
                    width: parent.width
                    text: model.title
                    highlighted: ListView.isCurrentItem
                    onClicked: {
                        listView.currentIndex = index
                        var pageId;
                        switch (model.source) {
                        case "busyIndicator":
                            pageId = busyIndicator;
                            break;
                        case "buttonPage":
                            pageId = buttonPage;
                            break;
                        case "checkboxPage":
                            pageId = checkboxPage;
                            break;
                        case "comboboxPage":
                            pageId = comboboxPage;
                            break;
                        case "delayButtonPage":
                            pageId = delayButtonPage;
                            break;
                        case "dialPage":
                            pageId = dialPage;
                            break;
                        case "dialogPage":
                            pageId = dialogPage;
                            break;
                        case "delegatePage":
                            pageId = delegatePage;
                            break;
                        case "framePage":
                            pageId = framePage;
                            break;
                        case "groupBoxPage":
                            pageId = groupBoxPage;
                            break;
                        case "pageIndicatorPage":
                            pageId = pageIndicatorPage;
                            break;
                        case "progressBarPage":
                            pageId = progressBarPage;
                            break;
                        case "radioButtonPage":
                            pageId = radioButtonPage;
                            break;
                        case "rangeSliderPage":
                            pageId = rangeSliderPage;
                            break;
                        case "scrollBarPage":
                            pageId = scrollBarPage;
                            break;
                        case "scrollIndicatorPage":
                            pageId = scrollIndicatorPage;
                            break;
                        case "sliderPage":
                            pageId = sliderPage;
                            break;
                        case "spinBoxPage":
                            pageId = spinBoxPage;
                            break;
                        case "stackViewPage":
                            pageId = stackViewPage;
                            break;
                        case "swipeViewPage":
                            pageId = swipeViewPage;
                            break;
                        case "switchPage":
                            pageId = switchPage;
                            break;
                        case "tabBarPage":
                            pageId = tabBarPage;
                            break;
                        case "toolTipPage":
                            pageId = toolTipPage;
                            break;
                        default:
                            pageId = tumblerPage;
                            break;
                        }
                        stackView.push(pageId)
                        drawer.close()
                    }
                }
                model: ListModel {
                    ListElement { title: "BusyIndicator"; source: "busyIndicator" }
                    ListElement { title: "Button"; source: "buttonPage" }
                    ListElement { title: "CheckBox"; source: "checkboxPage" }
                    ListElement { title: "ComboBox"; source: "comboboxPage" }
                    ListElement { title: "DelayButton"; source: "delayButtonPage" }
                    ListElement { title: "Dial"; source: "dialPage" }
                    ListElement { title: "Dialog"; source: "dialogPage" }
                    ListElement { title: "Delegates"; source: "delegatePage" }
                    ListElement { title: "Frame"; source: "framePage" }
                    ListElement { title: "GroupBox"; source: "groupBoxPage" }
                    ListElement { title: "PageIndicator"; source: "pageIndicatorPage" }
                    ListElement { title: "ProgressBar"; source: "progressBarPage" }
                    ListElement { title: "RadioButton"; source: "radioButtonPage" }
                    ListElement { title: "RangeSlider"; source: "rangeSliderPage" }
                    ListElement { title: "ScrollBar"; source: "scrollBarPage" }
                    ListElement { title: "ScrollIndicator"; source: "scrollIndicatorPage" }
                    ListElement { title: "Slider"; source: "sliderPage" }
                    ListElement { title: "SpinBox"; source: "spinBoxPage" }
                    ListElement { title: "StackView"; source: "stackViewPage" }
                    ListElement { title: "SwipeView"; source: "swipeViewPage" }
                    ListElement { title: "Switch"; source: "switchPage" }
                    ListElement { title: "TabBar"; source: "tabBarPage" }
                    ListElement { title: "ToolTip"; source: "toolTipPage" }
                    ListElement { title: "Tumbler"; source: "tumblerPage" }
                }
                ScrollIndicator.vertical: ScrollIndicator { }
            }
        }
    
        StackView {
            id: stackView
            anchors.fill: parent
            initialItem: Pane {
                id: pane
                Image {
                    id: logo
                    width: pane.availableWidth / 2
                    height: pane.availableHeight / 2
                    anchors.centerIn: parent
                    anchors.verticalCenterOffset: -50
                    fillMode: Image.PreserveAspectFit
                    source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/QQC/qt-logo.png"
                }
                Label {
                    text: "Qt Quick Controls 2 provides a set of controls that can be used to build complete interfaces in Qt Quick."
                    anchors.margins: 20
                    anchors.top: logo.bottom
                    anchors.left: parent.left
                    anchors.right: parent.right
                    anchors.bottom: arrow.top
                    horizontalAlignment: Label.AlignHCenter
                    verticalAlignment: Label.AlignVCenter
                    wrapMode: Label.Wrap
                }
                Image {
                    id: arrow
                    source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/QQC/arrow.png"
                    anchors.left: parent.left
                    anchors.bottom: parent.bottom
                }
            }
        }
    
        Dialog {
            id: aboutDialog
            modal: true
            focus: true
            title: "About"
            x: (window.width - width) / 2
            y: window.height / 6
            width: Math.min(window.width, window.height) / 3 * 2
            contentHeight: aboutColumn.height
            Column {
                id: aboutColumn
                spacing: 20
                Label {
                    width: aboutDialog.availableWidth
                    text: "The Qt Quick Controls 2 module delivers the next generation user interface controls based on Qt Quick."
                    wrapMode: Label.Wrap
                    font.pixelSize: 12
                }
                Label {
                    width: aboutDialog.availableWidth
                    text: "In comparison to the desktop-oriented Qt Quick Controls 1, Qt Quick Controls 2 "
                          + "are an order of magnitude simpler, lighter and faster, and are primarily targeted "
                          + "towards embedded and mobile platforms."
                    wrapMode: Label.Wrap
                    font.pixelSize: 12
                }
            }
        }
    
        Component {
            id: busyIndicator
    
            Page {
                // Almost every page shares the following Flickable item.
                // It should have been implemented as a shared component, but due to
                // WebAssembly application limitations of editing multiple files,
                // it has been been copied to each page.
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "BusyIndicator is used to indicate activity while content is being loaded,"
                              + " or when the UI is blocked waiting for a resource to become available."
                    }
                    BusyIndicator {
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
        }
    
        Component {
            id: buttonPage
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "Button presents a push-button that can be pushed or clicked by the user. "
                              + "Buttons are normally used to perform an action, or to answer a question."
                    }
                    ColumnLayout {
                        spacing: 20
                        anchors.horizontalCenter: parent.horizontalCenter
                        Button {
                            text: "First"
                            Layout.fillWidth: true
                        }
                        Button {
                            id: button
                            text: "Second"
                            highlighted: true
                            Layout.fillWidth: true
                        }
                        Button {
                            text: "Third"
                            enabled: false
                            Layout.fillWidth: true
                        }
                    }
                }
            }
        }
    
        Component {
            id: checkboxPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "CheckBox presents an option button that can be toggled on or off. "
                              + "Check boxes are typically used to select one or more options from a set of options."
                    }
                    Column {
                        spacing: 20
                        anchors.horizontalCenter: parent.horizontalCenter
    
                        CheckBox {
                            text: "First"
                            checked: true
                        }
                        CheckBox {
                            text: "Second"
                        }
                        CheckBox {
                            text: "Third"
                            checked: true
                            enabled: false
                        }
                    }
                }
            }
        }
    
        Component {
            id: comboboxPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "ComboBox is a combined button and popup list. It presents "
                              + "a list of options to the user that occupies minimal screen space."
                    }
                    ComboBox {
                        model: ["First", "Second", "Third"]
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "ComboBox can be made \l editable. An editable combo box auto-"
                              + "completes its text based on what is available in the model."
                    }
                    ComboBox {
                        editable: true
                        model: ListModel {
                            id: model
                            ListElement { text: "Banana" }
                            ListElement { text: "Apple" }
                            ListElement { text: "Coconut" }
                        }
                        onAccepted: {
                            if (find(editText) === -1)
                                model.append({text: editText})
                        }
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
        }
    
        Component {
            id: delayButtonPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "DelayButton is a checkable button that incorporates a delay before the "
                              + "button is activated. This delay prevents accidental presses."
                    }
                    DelayButton {
                        text: "DelayButton"
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
        }
    
        Component {
            id: dialPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "The Dial is similar to a traditional dial knob that is found on devices such as "
                              + "stereos or industrial equipment. It allows the user to specify a value within a range."
                    }
                    Dial {
                        value: 0.5
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
        }
    
        Component {
            id: dialogPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "Dialog is a popup that is mostly used for short-term tasks "
                              + "and brief communications with the user."
                    }
                    Button {
                        text: "Message"
                        anchors.horizontalCenter: parent.horizontalCenter
                        // width: buttonWidth
                        onClicked: messageDialog.open()
                        Dialog {
                            id: messageDialog
                            x: (parent.width - width) / 2
                            y: (parent.height - height) / 2
                            title: "Message"
                            Label {
                                text: "Lorem ipsum dolor sit amet..."
                            }
                        }
                    }
                    Button {
                        id: button
                        text: "Confirmation"
                        anchors.horizontalCenter: parent.horizontalCenter
                        // width: buttonWidth
                        onClicked: confirmationDialog.open()
                        Dialog {
                            id: confirmationDialog
                            x: (parent.width - width) / 2
                            y: (parent.height - height) / 2
                            parent: Overlay.overlay
                            modal: true
                            title: "Confirmation"
                            standardButtons: Dialog.Yes | Dialog.No
                            Column {
                                spacing: 20
                                anchors.fill: parent
                                Label {
                                    text: "The document has been modified.\nDo you want to save your changes?"
                                }
                                CheckBox {
                                    text: "Do not ask again"
                                    anchors.right: parent.right
                                }
                            }
                        }
                    }
                    Button {
                        text: "Content"
                        anchors.horizontalCenter: parent.horizontalCenter
                        // width: buttonWidth
                        onClicked: contentDialog.open()
                        Dialog {
                            id: contentDialog
                            x: (parent.width - width) / 2
                            y: (parent.height - height) / 2
                            width: Math.min(dialogPage.width, dialogPage.height) / 3 * 2
                            contentHeight: logo.height * 2
                            parent: Overlay.overlay
                            modal: true
                            title: "Content"
                            standardButtons: Dialog.Close
                            Flickable {
                                id: flickable
                                clip: true
                                anchors.fill: parent
                                contentHeight: column.height
                                Column {
                                    id: column
                                    spacing: 20
                                    width: parent.width
                                    Image {
                                        id: logo
                                        width: parent.width / 2
                                        anchors.horizontalCenter: parent.horizontalCenter
                                        fillMode: Image.PreserveAspectFit
                                        source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/QQC/qt-logo.png"
                                    }
                                    Label {
                                        width: parent.width
                                        text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc finibus "
                                              + "in est quis laoreet. Interdum et malesuada fames ac ante ipsum primis "
                                              + "in faucibus. Curabitur eget justo sollicitudin enim faucibus bibendum. "
                                              + "Suspendisse potenti. Vestibulum cursus consequat mauris id sollicitudin. "
                                              + "Duis facilisis hendrerit consectetur. Curabitur sapien tortor, efficitur "
                                              + "id auctor nec, efficitur et nisl. Ut venenatis eros in nunc placerat, "
                                              + "eu aliquam enim suscipit."
                                        wrapMode: Label.Wrap
                                    }
                                }
                                ScrollIndicator.vertical: ScrollIndicator {
                                    parent: contentDialog.contentItem
                                    anchors.top: flickable.top
                                    anchors.bottom: flickable.bottom
                                    anchors.right: parent.right
                                    anchors.rightMargin: -contentDialog.rightPadding + 1
                                }
                            }
                        }
                    }
                    Button {
                        text: "Input"
                        anchors.horizontalCenter: parent.horizontalCenter
                        // width: buttonWidth
                        onClicked: inputDialog.open()
                        Dialog {
                            id: inputDialog
                            x: (parent.width - width) / 2
                            y: (parent.height - height) / 2
                            parent: Overlay.overlay
                            focus: true
                            modal: true
                            title: "Input"
                            standardButtons: Dialog.Ok | Dialog.Cancel
                            ColumnLayout {
                                spacing: 20
                                anchors.fill: parent
                                Label {
                                    elide: Label.ElideRight
                                    text: "Please enter the credentials:"
                                    Layout.fillWidth: true
                                }
                                TextField {
                                    focus: true
                                    placeholderText: "Username"
                                    Layout.fillWidth: true
                                }
                                TextField {
                                    placeholderText: "Password"
                                    echoMode: TextField.PasswordEchoOnEdit
                                    Layout.fillWidth: true
                                }
                            }
                        }
                    }
                }
            }
        }
    
        Component {
            id: delegatePage
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                property var delegateComponentMap: {
                    "ItemDelegate": itemDelegateComponent,
                    "SwipeDelegate": swipeDelegateComponent,
                    "CheckDelegate": checkDelegateComponent,
                    "RadioDelegate": radioDelegateComponent,
                    "SwitchDelegate": switchDelegateComponent
                }
                Component {
                    id: itemDelegateComponent
                    ItemDelegate {
                        text: labelText
                        width: parent.width
                    }
                }
                Component {
                    id: swipeDelegateComponent
                    SwipeDelegate {
                        id: swipeDelegate
                        text: labelText
                        width: parent.width
                        Component {
                            id: removeComponent
                            Rectangle {
                                color: SwipeDelegate.pressed ? "#333" : "#444"
                                width: parent.width
                                height: parent.height
                                clip: true
                                SwipeDelegate.onClicked: view.model.remove(ourIndex)
                                Label {
                                    font.pixelSize: swipeDelegate.font.pixelSize
                                    text: "Remove"
                                    color: "white"
                                    anchors.centerIn: parent
                                }
                            }
                        }
                        swipe.left: removeComponent
                        swipe.right: removeComponent
                    }
                }
                Component {
                    id: checkDelegateComponent
    
                    CheckDelegate {
                        text: labelText
                        width: parent.width
                    }
                }
                ButtonGroup {
                    id: radioButtonGroup
                }
                Component {
                    id: radioDelegateComponent
                    RadioDelegate {
                        text: labelText
                        ButtonGroup.group: radioButtonGroup
                    }
                }
                Component {
                    id: switchDelegateComponent
                    SwitchDelegate {
                        text: labelText
                    }
                }
                ColumnLayout {
                    id: column
                    spacing: 40
                    anchors.fill: parent
                    anchors.topMargin: 20
                    Label {
                        Layout.fillWidth: true
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "Delegate controls are used as delegates in views such as ListView."
                    }
                    ListView {
                        id: listView
                        Layout.fillWidth: true
                        Layout.fillHeight: true
                        clip: true
                        model: ListModel {
                            ListElement { type: "ItemDelegate"; text: "ItemDelegate" }
                            ListElement { type: "ItemDelegate"; text: "ItemDelegate" }
                            ListElement { type: "ItemDelegate"; text: "ItemDelegate" }
                            ListElement { type: "SwipeDelegate"; text: "SwipeDelegate" }
                            ListElement { type: "SwipeDelegate"; text: "SwipeDelegate" }
                            ListElement { type: "SwipeDelegate"; text: "SwipeDelegate" }
                            ListElement { type: "CheckDelegate"; text: "CheckDelegate" }
                            ListElement { type: "CheckDelegate"; text: "CheckDelegate" }
                            ListElement { type: "CheckDelegate"; text: "CheckDelegate" }
                            ListElement { type: "RadioDelegate"; text: "RadioDelegate" }
                            ListElement { type: "RadioDelegate"; text: "RadioDelegate" }
                            ListElement { type: "RadioDelegate"; text: "RadioDelegate" }
                            ListElement { type: "SwitchDelegate"; text: "SwitchDelegate" }
                            ListElement { type: "SwitchDelegate"; text: "SwitchDelegate" }
                            ListElement { type: "SwitchDelegate"; text: "SwitchDelegate" }
                        }
                        section.property: "type"
                        section.delegate: Pane {
                            width: listView.width
                            height: sectionLabel.implicitHeight + 20
                            Label {
                                id: sectionLabel
                                text: section
                                anchors.centerIn: parent
                            }
                        }
                        delegate: Loader {
                            id: delegateLoader
                            property string labelText: text
                            property ListView view: listView
                            property int ourIndex: index
                            width: listView.width
                            sourceComponent: delegateComponentMap[text]
    
                            // Can't find a way to do this in the SwipeDelegate component itself,
                            // so do it here instead.
                            ListView.onRemove: SequentialAnimation {
                                PropertyAction {
                                    target: delegateLoader
                                    property: "ListView.delayRemove"
                                    value: true
                                }
                                NumberAnimation {
                                    target: item
                                    property: "height"
                                    to: 0
                                    easing.type: Easing.InOutQuad
                                }
                                PropertyAction {
                                    target: delegateLoader
                                    property: "ListView.delayRemove"
                                    value: false
                                }
                            }
                        }
                    }
                }
            }
        }
    
        Component {
            id: framePage
    
            Page {
                id: _framePage
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                readonly property int itemWidth: Math.max(button.implicitWidth, Math.min(button.implicitWidth * 3, _framePage.availableWidth / 3 * 2))
    
                Column {
                    spacing: 40
                    width: parent.width
    
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "Frame is used to layout a logical group of controls together, within a visual frame."
                    }
    
                    Frame {
                        anchors.horizontalCenter: parent.horizontalCenter
                        Column {
                            spacing: 20
                            width: _framePage.itemWidth
                            RadioButton {
                                text: "First"
                                checked: true
                                width: parent.width
                            }
                            RadioButton {
                                id: button
                                text: "Second"
                                width: parent.width
                            }
                            RadioButton {
                                text: "Third"
                                width: parent.width
                            }
                        }
                    }
                }
            }
        }
    
        Component {
            id: groupBoxPage
    
            Page {
                id: _groupBBoxPage
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                readonly property int itemWidth: Math.max(button.implicitWidth, Math.min(button.implicitWidth * 3, _groupBBoxPage.availableWidth / 3 * 2))
    
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "A GroupBox provides a frame, a title on top of it, and a logical group of controls within that frame."
                    }
                    GroupBox {
                        title: "Title"
                        anchors.horizontalCenter: parent.horizontalCenter
                        Column {
                            spacing: 20
                            width: _groupBBoxPage.itemWidth
                            RadioButton {
                                text: "First"
                                checked: true
                                width: parent.width
                            }
                            RadioButton {
                                id: button
                                text: "Second"
                                width: parent.width
                            }
                            RadioButton {
                                text: "Third"
                                width: parent.width
                            }
                        }
                    }
                }
            }
        }
    
        Component {
            id: pageIndicatorPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "PageIndicator is used to indicate the currently active page in a container of pages."
                    }
                    PageIndicator {
                        count: 5
                        currentIndex: 2
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
        }
    
        Component {
            id: progressBarPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "ProgressBar indicates the progress of an operation. It can be set in an "
                              + "indeterminate mode to indicate that the length of the operation is unknown."
                    }
                    ProgressBar {
                        id: bar
                        value: 0.5
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                    ProgressBar {
                        indeterminate: true
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
    
        }
    
        Component {
            id: radioButtonPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "RadioButton presents an option button that can be toggled on or off. "
                              + "Radio buttons are typically used to select one option from a set of options."
                    }
                    Column {
                        spacing: 20
                        anchors.horizontalCenter: parent.horizontalCenter
    
                        RadioButton {
                            text: "First"
                        }
                        RadioButton {
                            text: "Second"
                            checked: true
                        }
                        RadioButton {
                            text: "Third"
                            enabled: false
                        }
                    }
                }
            }
        }
    
        Component {
            id: rangeSliderPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "RangeSlider is used to select a range specified by two values, by sliding each handle along a track."
                    }
                    RangeSlider {
                        id: slider
                        first.value: 0.25
                        second.value: 0.75
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                    RangeSlider {
                        orientation: Qt.Vertical
                        first.value: 0.25
                        second.value: 0.75
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
        }
    
        Component {
            id: scrollBarPage
    
            Flickable {
                id: flickable
                contentHeight: pane.height
                Pane {
                    id: pane
                    width: flickable.width
                    height: flickable.height * 1.25
                    Column {
                        id: column
                        spacing: 40
                        width: parent.width
                        Label {
                            width: parent.width
                            wrapMode: Label.Wrap
                            horizontalAlignment: Qt.AlignHCenter
                            text: "ScrollBar is an interactive bar that can be used to scroll to a specific position. "
                                  + "A scroll bar can be either vertical or horizontal, and can be attached to any Flickable, "
                                  + "such as ListView and GridView."
                        }
                        Image {
                            rotation: 90
                            source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/QQC/arrows.png"
                            anchors.horizontalCenter: parent.horizontalCenter
                        }
                    }
                }
                ScrollBar.vertical: ScrollBar { }
            }
        }
        Component {
            id: scrollIndicatorPage
    
            Flickable {
                id: flickable
                contentHeight: pane.height
                Pane {
                    id: pane
                    width: flickable.width
                    height: flickable.height * 1.25
                    Column {
                        id: column
                        spacing: 40
                        width: parent.width
                        Label {
                            width: parent.width
                            wrapMode: Label.Wrap
                            horizontalAlignment: Qt.AlignHCenter
                            text: "ScrollIndicator is a non-interactive indicator that indicates the current scroll position. "
                                  + "A scroll indicator can be either vertical or horizontal, and can be attached to any Flickable, "
                                  + "such as ListView and GridView."
                        }
                        Image {
                            rotation: 90
                            source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/QQC/arrows.png"
                            anchors.horizontalCenter: parent.horizontalCenter
                        }
                    }
                }
                ScrollIndicator.vertical: ScrollIndicator { }
            }
        }
    
        Component {
            id: sliderPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "Slider is used to select a value by sliding a handle along a track."
                    }
                    Slider {
                        id: slider
                        value: 0.5
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                    Slider {
                        orientation: Qt.Vertical
                        value: 0.5
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
        }
    
        Component {
            id: spinBoxPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "SpinBox allows the user to choose an integer value by clicking the up or down indicator buttons, "
                              + "by pressing up or down on the keyboard, or by entering a text value in the input field."
                    }
                    SpinBox {
                        id: box
                        value: 50
                        anchors.horizontalCenter: parent.horizontalCenter
                        editable: true
                    }
                }
            }
    
    
        }
    
        Component {
            id: stackViewPage
    
            StackView {
                id: stackView
                initialItem: page
                Component {
                    id: page
    
                    Pane {
                        id: pane
                        width: parent ? parent.width : 0 // TODO: fix null parent on destruction
                        Column {
                            spacing: 40
                            width: parent.width
                            Label {
                                width: parent.width
                                wrapMode: Label.Wrap
                                horizontalAlignment: Qt.AlignHCenter
                                text: "StackView provides a stack-based navigation model which can be used with a set of interlinked pages. "
                                      + "Items are pushed onto the stack as the user navigates deeper into the material, and popped off again "
                                      + "when he chooses to go back."
                            }
                            Button {
                                id: button
                                text: "Push"
                                anchors.horizontalCenter: parent.horizontalCenter
                                width: Math.max(button.implicitWidth, Math.min(button.implicitWidth * 2, pane.availableWidth / 3))
                                onClicked: stackView.push(page)
                            }
                            Button {
                                text: "Pop"
                                enabled: stackView.depth > 1
                                width: Math.max(button.implicitWidth, Math.min(button.implicitWidth * 2, pane.availableWidth / 3))
                                anchors.horizontalCenter: parent.horizontalCenter
                                onClicked: stackView.pop()
                            }
                        }
                    }
                }
            }
        }
    
        Component {
            id: swipeViewPage
    
            Pane {
                id: pane
                SwipeView {
                    id: view
                    currentIndex: 1
                    anchors.fill: parent
                    Repeater {
                        model: 3
                        Pane {
                            width: view.width
                            height: view.height
                            Column {
                                spacing: 40
                                width: parent.width
    
                                Label {
                                    width: parent.width
                                    wrapMode: Label.Wrap
                                    horizontalAlignment: Qt.AlignHCenter
                                    text: "SwipeView provides a navigation model that simplifies horizontal paged scrolling. "
                                          + "The page indicator on the bottom shows which is the presently active page."
                                }
                                Image {
                                    source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/QQC/arrows.png"
                                    anchors.horizontalCenter: parent.horizontalCenter
                                }
                            }
                        }
                    }
                }
    
                PageIndicator {
                    count: view.count
                    currentIndex: view.currentIndex
                    anchors.bottom: parent.bottom
                    anchors.horizontalCenter: parent.horizontalCenter
                }
            }
        }
    
        Component {
            id: switchPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "Switch is an option button that can be dragged or toggled on or off. "
                              + "Switches are typically used to select between two states."
                    }
                    Column {
                        spacing: 20
                        anchors.horizontalCenter: parent.horizontalCenter
    
                        Switch {
                            text: "First"
                        }
                        Switch {
                            text: "Second"
                            checked: true
                        }
                        Switch {
                            text: "Third"
                            enabled: false
                        }
                    }
                }
            }
        }
    
        Component {
            id: tabBarPage
    
            Page {
                SwipeView {
                    id: swipeView
                    anchors.fill: parent
                    currentIndex: tabBar.currentIndex
                    Repeater {
                        model: 3
                        Pane {
                            width: swipeView.width
                            height: swipeView.height
                            Column {
                                spacing: 40
                                width: parent.width
                                Label {
                                    width: parent.width
                                    wrapMode: Label.Wrap
                                    horizontalAlignment: Qt.AlignHCenter
                                    text: "TabBar is a bar with icons or text which allows the user "
                                          + "to switch between different subtasks, views, or modes."
                                }
                                Image {
                                    source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/QQC/arrows.png"
                                    anchors.horizontalCenter: parent.horizontalCenter
                                }
                            }
                        }
                    }
                }
    
                footer: TabBar {
                    id: tabBar
                    currentIndex: swipeView.currentIndex
                    TabButton {
                        text: "First"
                    }
                    TabButton {
                        text: "Second"
                    }
                    TabButton {
                        text: "Third"
                    }
                }
            }
        }
    
        Component {
            id: toolTipPage
    
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "A tool tip is a short piece of text that informs the user of a control's function."
                    }
                    Button {
                        text: "Tip"
                        anchors.horizontalCenter: parent.horizontalCenter
                        ToolTip.timeout: 5000
                        ToolTip.visible: pressed
                        ToolTip.text: "This is a tool tip."
                    }
                }
            }
        }
    
        Component {
            id:  tumblerPage
            Page {
                Flickable {
                    anchors.fill: parent
                    contentHeight: pane.implicitHeight
                    flickableDirection: Flickable.AutoFlickIfNeeded
                    Pane {
                        id: pane1
                        width: parent.width
                    }
                    ScrollIndicator.vertical: ScrollIndicator { }
                }
                Column {
                    spacing: 40
                    width: parent.width
                    Label {
                        width: parent.width
                        wrapMode: Label.Wrap
                        horizontalAlignment: Qt.AlignHCenter
                        text: "Tumbler is used to select a value by spinning a wheel."
                    }
                    Tumbler {
                        model: 10
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }
        }
    }
    
    
    
  • Custom Controls

    UI controls may be created from the basic QML types. This example shows a Dial gauge, created completely from the very basic QML types.

    Load this example
    /****************************************************************************
    **
    ** Copyright (C) 2020 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.14
    import QtQuick.Window 2.2
    
    Rectangle {
        color: "#545454"
        width: 640; height: 480
    
        Item {
            id: root
            property real value : slider.x * 100 / (container.width - 32)
            anchors.centerIn: parent
            width: 210; height: 210
            Image {
                source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/customControls/background.png"
            }
            Image {
                x: 96
                y: 35
                source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/customControls/needle_shadow.png"
                transform: Rotation {
                    origin.x: 9; origin.y: 67
                    angle: needleRotation.angle
                }
            }
            Image {
                id: needle
                x: 98; y: 33
                antialiasing: true
                source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/customControls/needle.png"
                transform: Rotation {
                    id: needleRotation
                    origin.x: 5; origin.y: 65
                    // needle angle
                    angle: Math.min(Math.max(-130, root.value*2.6 - 130), 133)
                    Behavior on angle {
                        SpringAnimation {
                            spring: 1.4
                            damping: .15
                        }
                    }
                }
            }
            Image { x: 21; y: 18; source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/customControls/overlay.png" }
        }
    
        Rectangle {
            id: container
            property int oldWidth: 0
            anchors { bottom: parent.bottom; left: parent.left
                right: parent.right; leftMargin: 20; rightMargin: 20
                bottomMargin: 10
            }
            height: 16
            radius: 8
            opacity: 0.7
            antialiasing: true
            gradient: Gradient {
                GradientStop { position: 0.0; color: "gray" }
                GradientStop { position: 1.0; color: "white" }
            }
    
            onWidthChanged: {
                if (oldWidth === 0) {
                    oldWidth = width;
                    return
                }
    
                var desiredPercent = slider.x * 100 / (oldWidth - 32)
                slider.x = desiredPercent * (width - 32) / 100
                oldWidth = width
            }
    
            Rectangle {
                id: slider
                x: 1; y: 1; width: 30; height: 14
                radius: 6
                antialiasing: true
                gradient: Gradient {
                    GradientStop { position: 0.0; color: "#424242" }
                    GradientStop { position: 1.0; color: "black" }
                }
    
                MouseArea {
                    anchors.fill: parent
                    anchors.margins: -16 // Increase mouse area a lot outside the slider
                    drag.target: parent; drag.axis: Drag.XAxis
                    drag.minimumX: 2; drag.maximumX: container.width - 32
                }
            }
        }
    }
    
  • 3D Charts go live

    QML has a rich selection of controls – even ready-made 2D and 3D chart types. If you have static or dynamic data, charts provides you with a convenient way to render the data in 3D bars or surfaces.

    Load this example
    /****************************************************************************
    **
    ** Copyright (C) 2020 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.14
    import QtQuick.Layouts 1.3
    import QtDataVisualization 1.0
    import QtQuick.Controls 2.14
    import QtQuick.Controls.Styles 1.4
    
    Rectangle {
        id: mainView
        width: 640
        height: 480
    
        ListModel {
            id: data
            ListElement{ row: "0"; col: "0"; longitude: "20.0"; latitude: "10.0"; pop_density: "4.75"; }
            ListElement{ row: "1"; col: "0"; longitude: "21.1"; latitude: "10.3"; pop_density: "3.00"; }
            ListElement{ row: "2"; col: "0"; longitude: "22.5"; latitude: "10.7"; pop_density: "1.24"; }
            ListElement{ row: "3"; col: "0"; longitude: "24.0"; latitude: "10.5"; pop_density: "2.53"; }
            ListElement{ row: "0"; col: "1"; longitude: "20.2"; latitude: "11.2"; pop_density: "3.55"; }
            ListElement{ row: "1"; col: "1"; longitude: "21.3"; latitude: "11.5"; pop_density: "3.03"; }
            ListElement{ row: "2"; col: "1"; longitude: "22.6"; latitude: "11.7"; pop_density: "3.46"; }
            ListElement{ row: "3"; col: "1"; longitude: "23.4"; latitude: "11.5"; pop_density: "4.12"; }
            ListElement{ row: "0"; col: "2"; longitude: "20.2"; latitude: "12.3"; pop_density: "3.37"; }
            ListElement{ row: "1"; col: "2"; longitude: "21.1"; latitude: "12.4"; pop_density: "2.98"; }
            ListElement{ row: "2"; col: "2"; longitude: "22.5"; latitude: "12.1"; pop_density: "3.33"; }
            ListElement{ row: "3"; col: "2"; longitude: "23.3"; latitude: "12.7"; pop_density: "3.23"; }
            ListElement{ row: "0"; col: "3"; longitude: "20.7"; latitude: "13.3"; pop_density: "5.34"; }
            ListElement{ row: "1"; col: "3"; longitude: "21.5"; latitude: "13.2"; pop_density: "4.54"; }
            ListElement{ row: "2"; col: "3"; longitude: "22.4"; latitude: "13.6"; pop_density: "4.65"; }
            ListElement{ row: "3"; col: "3"; longitude: "23.2"; latitude: "13.4"; pop_density: "6.67"; }
            ListElement{ row: "0"; col: "4"; longitude: "20.6"; latitude: "15.0"; pop_density: "6.01"; }
            ListElement{ row: "1"; col: "4"; longitude: "21.3"; latitude: "14.6"; pop_density: "5.83"; }
            ListElement{ row: "2"; col: "4"; longitude: "22.5"; latitude: "14.8"; pop_density: "7.32"; }
            ListElement{ row: "3"; col: "4"; longitude: "23.7"; latitude: "14.3"; pop_density: "6.90"; }
        }
    
        GridLayout {
            id: gridLayout
            columns: 2
            Layout.fillHeight: true
            Layout.fillWidth: true
            anchors.top: mainView.top
            anchors.bottom: mainView.bottom
            anchors.left: mainView.left
            anchors.right: mainView.right
    
            Rectangle {
                Layout.fillHeight: true
                Layout.fillWidth: true
                border.color: surfaceGraph.theme.gridLineColor
                border.width: 2
    
                Surface3D {
                    id: surfaceGraph
                    anchors.fill: parent
                    anchors.margins: parent.border.width
                    theme: Theme3D {
                        type: Theme3D.ThemePrimaryColors
                        font.pointSize: 60
                    }
                    scene.activeCamera.cameraPreset: Camera3D.CameraPresetIsometricLeftHigh
    
                    Surface3DSeries {
                        itemLabelFormat: "Pop density at (@xLabel N, @zLabel E): @yLabel"
                        ItemModelSurfaceDataProxy {
                            itemModel: data
                            // The surface data points are not neatly lined up in rows and columns,
                            // so we define explicit row and column roles.
                            rowRole: "row"
                            columnRole: "col"
                            xPosRole: "latitude"
                            zPosRole: "longitude"
                            yPosRole: "pop_density"
                        }
                    }
                }
            }
    
            // We'll use one grid cell for buttons
            Rectangle {
                Layout.fillHeight: true
                Layout.fillWidth: true
    
                GridLayout {
                    anchors.right: parent.right
                    anchors.left: parent.left
                    anchors.top: parent.top
                    anchors.bottom: parent.bottom
                    columns: 2
    
                    Button {
                        Layout.minimumWidth: parent.width / 2
                        Layout.fillHeight: true
                        Layout.fillWidth: true
                        text: "Clear Selections"
                        onClicked: clearSelections() // call a helper function to keep button itself simpler
                    }
    
                    Button {
                        Layout.minimumWidth: parent.width / 2
                        Layout.fillHeight: true
                        Layout.fillWidth: true
                        text: "Quit - NA"
                    }
    
                    Button {
                        Layout.fillHeight: true
                        Layout.fillWidth: true
                        text: "Reset Cameras"
                        onClicked: resetCameras() // call a helper function to keep button itself simpler
                    }
    
                    Button {
                        Layout.fillHeight: true
                        Layout.fillWidth: true
                        text: "Toggle Mesh \n Styles"
                        onClicked: toggleMeshStyle() // call a helper function to keep button itself simpler
                    }
                }
            }
    
            Rectangle {
                Layout.fillHeight: true
                Layout.fillWidth: true
                border.color: scatterGraph.theme.gridLineColor
                border.width: 2
    
                Scatter3D {
                    id: scatterGraph
                    anchors.fill: parent
                    anchors.margins: parent.border.width
                    theme: Theme3D {
                        type: Theme3D.ThemeDigia
                        font.pointSize: 60
                    }
                    scene.activeCamera.cameraPreset: Camera3D.CameraPresetIsometricLeftHigh
    
                    Scatter3DSeries {
                        itemLabelFormat: "Pop density at (@xLabel N, @zLabel E): @yLabel"
                        ItemModelScatterDataProxy {
                            itemModel: data
                            // Mapping model roles to scatter series item coordinates.
                            xPosRole: "latitude"
                            zPosRole: "longitude"
                            yPosRole: "pop_density"
                        }
                    }
                }
            }
    
            Rectangle {
                Layout.fillHeight: true
                Layout.fillWidth: true
                border.color: barGraph.theme.gridLineColor
                border.width: 2
    
                Bars3D {
                    id: barGraph
                    anchors.fill: parent
                    anchors.margins: parent.border.width
                    theme: Theme3D {
                        type: Theme3D.ThemeQt
                        font.pointSize: 60
                    }
                    selectionMode: AbstractGraph3D.SelectionItemAndRow | AbstractGraph3D.SelectionSlice
                    scene.activeCamera.cameraPreset: Camera3D.CameraPresetIsometricLeftHigh
    
                    Bar3DSeries {
                        itemLabelFormat: "@seriesName: @valueLabel"
                        name: "Population density"
    
                        ItemModelBarDataProxy {
                            itemModel: data
                            // Mapping model roles to bar series rows, columns, and values.
                            rowRole: "row"
                            columnRole: "col"
                            valueRole: "pop_density"
                        }
                    }
                }
            }
        }
    
        function clearSelections() {
            barGraph.clearSelection()
            scatterGraph.clearSelection()
            surfaceGraph.clearSelection()
        }
    
        function resetCameras() {
            surfaceGraph.scene.activeCamera.cameraPreset = Camera3D.CameraPresetIsometricLeftHigh
            scatterGraph.scene.activeCamera.cameraPreset = Camera3D.CameraPresetIsometricLeftHigh
            barGraph.scene.activeCamera.cameraPreset = Camera3D.CameraPresetIsometricLeftHigh
            surfaceGraph.scene.activeCamera.zoomLevel = 100.0
            scatterGraph.scene.activeCamera.zoomLevel = 100.0
            barGraph.scene.activeCamera.zoomLevel = 100.0
        }
    
        function toggleMeshStyle() {
            if (barGraph.seriesList[0].meshSmooth === true) {
                barGraph.seriesList[0].meshSmooth = false
                if (surfaceGraph.seriesList[0].flatShadingSupported)
                    surfaceGraph.seriesList[0].flatShadingEnabled = true
                scatterGraph.seriesList[0].meshSmooth = false
            } else {
                barGraph.seriesList[0].meshSmooth = true
                surfaceGraph.seriesList[0].flatShadingEnabled = false
                scatterGraph.seriesList[0].meshSmooth = true
            }
        }
    }
    
  • Same Game

    Like candy crasher? This is what you must try. Even creating a simple game requires just a few lines of QML code.

    Load this example
    /****************************************************************************
    **
    ** Copyright (C) 2020 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.12
    import QtQuick.Controls 2.5
    import QtQuick.Particles 2.12
    
    Rectangle {
        id: screen
    
        property int maxColumn: 10
        property int maxRow: 15
        property int maxIndex: maxColumn * maxRow
        property var board: new Array(maxIndex);
    
        // NOTE! The JavaScript is in this file to be accessible for the demo users
        // Normally the JavaScript functions should be in a separate .js file
    
        //Index function used instead of a 2D array
        function index(column, row) {
            return column + (row * maxColumn);
        }
    
        function startNewGame() {
            //Delete blocks from previous game
            for (var i = 0; i < maxIndex; i++) {
                if (board[i] != null)
                    board[i].destroy();
            }
    
            //Calculate board size
            maxColumn = Math.floor(gameCanvas.width / gameCanvas.blockSize);
            maxRow = Math.floor(gameCanvas.height / gameCanvas.blockSize);
            maxIndex = maxRow * maxColumn;
    
            //Initialize Board
            board = new Array(maxIndex);
            gameCanvas.score = 0;
            for (var column = 0; column < maxColumn; column++) {
                for (var row = 0; row < maxRow; row++) {
                    board[index(column, row)] = null;
                    createBlock(column, row);
                }
            }
        }
    
        function createBlock(column, row) {
            var dynamicObject = boomBlockComponent.createObject(gameCanvas);
            if (dynamicObject == null) {
                console.log("error creating block");
                console.log(boomBlockComponent.errorString());
                return false;
            }
            dynamicObject.type = Math.floor(Math.random() * 3);
            dynamicObject.x = column * gameCanvas.blockSize;
            dynamicObject.y = row * gameCanvas.blockSize;
            dynamicObject.width = gameCanvas.blockSize;
            dynamicObject.height = gameCanvas.blockSize;
            dynamicObject.spawned = true;
            board[index(column, row)] = dynamicObject;
            return true;
        }
    
        property int fillFound; //Set after a floodFill call to the number of blocks found
        property var floodBoard; //Set to 1 if the floodFill reaches off that node
    
        function handleClick(xPos, yPos) {
            var column = Math.floor(xPos / gameCanvas.blockSize);
            var row = Math.floor(yPos / gameCanvas.blockSize);
            if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
                return;
            if (board[index(column, row)] == null)
                return;
            //If it's a valid block, remove it and all connected (does nothing if it's not connected)
            floodFill(column, row, -1);
            if (fillFound <= 0)
                return;
            gameCanvas.score += (fillFound - 1) * (fillFound - 1);
            shuffleDown();
            victoryCheck();
        }
    
        function floodFill(column, row, type) {
            if (board[index(column, row)] == null)
                return;
            var first = false;
            if (type == -1) {
                first = true;
                type = board[index(column, row)].type;
    
                //Flood fill initialization
                fillFound = 0;
                floodBoard = new Array(maxIndex);
            }
            if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
                return;
            if (floodBoard[index(column, row)] == 1 || (!first && type != board[index(column, row)].type))
                return;
            floodBoard[index(column, row)] = 1;
            floodFill(column + 1, row, type);
            floodFill(column - 1, row, type);
            floodFill(column, row + 1, type);
            floodFill(column, row - 1, type);
            if (first == true && fillFound == 0)
                return;     //Can't remove single blocks
            board[index(column, row)].dying = true;
            board[index(column, row)] = null;
            fillFound += 1;
        }
    
        function shuffleDown() {
            //Fall down
            for (var column = 0; column < maxColumn; column++) {
                var fallDist = 0;
                for (var row = maxRow - 1; row >= 0; row--) {
                    if (board[index(column, row)] == null) {
                        fallDist += 1;
                    } else {
                        if (fallDist > 0) {
                            var obj = board[index(column, row)];
                            obj.y = (row + fallDist) * gameCanvas.blockSize;
                            board[index(column, row + fallDist)] = obj;
                            board[index(column, row)] = null;
                        }
                    }
                }
            }
            //Fall to the left
            fallDist = 0;
            for (column = 0; column < maxColumn; column++) {
                if (board[index(column, maxRow - 1)] == null) {
                    fallDist += 1;
                } else {
                    if (fallDist > 0) {
                        for (row = 0; row < maxRow; row++) {
                            obj = board[index(column, row)];
                            if (obj == null)
                                continue;
                            obj.x = (column - fallDist) * gameCanvas.blockSize;
                            board[index(column - fallDist, row)] = obj;
                            board[index(column, row)] = null;
                        }
                    }
                }
            }
        }
    
        function victoryCheck() {
            //Award bonus points if no blocks left
            var deservesBonus = true;
            for (var column = maxColumn - 1; column >= 0; column--)
                if (board[index(column, maxRow - 1)] != null)
                    deservesBonus = false;
            if (deservesBonus) {
                gameCanvas.score += 500;
                gameFinishedDialog.won = true;
            }
    
            //Check whether game has finished
            if (deservesBonus || !(floodMoveCheck(0, maxRow - 1, -1))) {
                gameFinishedDialog.open();
            }
        }
    
        //only floods up and right, to see if it can find adjacent same-typed blocks
        function floodMoveCheck(column, row, type) {
            if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
                return false;
            if (board[index(column, row)] == null)
                return false;
            var myType = board[index(column, row)].type;
            if (type == myType)
                return true;
            return floodMoveCheck(column + 1, row, myType) || floodMoveCheck(column, row - 1, board[index(column, row)].type);
        }
    
        width: 640; height: 480
    
        Item {
            width: parent.width
            anchors { top: parent.top; bottom: toolBar.top }
    
            Image {
                id: background
                anchors.fill: parent
                source: "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/sameGame/background.jpg"
                fillMode: Image.PreserveAspectCrop
            }
    
            Item {
                id: gameCanvas
                property int score: 0
                property int blockSize: 40
    
                anchors.centerIn: parent
                width: parent.width - (parent.width % blockSize);
                height: parent.height - (parent.height % blockSize);
    
                MouseArea {
                    anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y);
                }
            }
        }
    
        Dialog {
            id: gameFinishedDialog
    
            property bool won: false
    
            anchors.centerIn: parent
    
            title: won ? "You won the game!" : "Game over!"
        }
    
        Rectangle {
            id: toolBar
            width: parent.width; height: newGameButton.height
            anchors.bottom: screen.bottom
    
            Button {
                id: newGameButton
                anchors { left: parent.left; verticalCenter: parent.verticalCenter }
                text: "New Game"
                onClicked: startNewGame()
            }
    
            Label {
                id: score
                anchors { right: parent.right; rightMargin: 10; verticalCenter: parent.verticalCenter }
                text: "Score: " + gameCanvas.score
                color: "black"
            }
        }
    
        Component {
            id: boomBlockComponent
    
            Item {
                id: block
    
                property int type: 0
                property bool dying: false
    
                property bool spawned: false
    
                Behavior on x {
                    enabled: spawned;
                    SpringAnimation{ spring: 2; damping: 0.2 }
                }
                Behavior on y {
                    SpringAnimation{ spring: 2; damping: 0.2 }
                }
    
                Image {
                    id: img
    
                    anchors.fill: parent
                    source: {
                        if (type == 0)
                            return "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/sameGame/redStone.png";
                        else if (type == 1)
                            return "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/sameGame/blueStone.png";
                        else
                            return "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/sameGame/greenStone.png";
                    }
                    opacity: 0
    
                    Behavior on opacity {
                        NumberAnimation { properties:"opacity"; duration: 200 }
                    }
                }
    
                ParticleSystem {
                    id: sys
                    anchors.centerIn: parent
                    ImageParticle {
                        source: {
                            if (type == 0)
                                return "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/sameGame/redStar.png";
                            else if (type == 1)
                                return "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/sameGame/blueStar.png";
                            else
                                return "https://cdn2.hubspot.net/hubfs/149513/QML/playground/examples/images/sameGame/greenStar.png";
                        }
                        rotationVelocityVariation: 360
                    }
    
                    Emitter {
                        id: particles
                        anchors.centerIn: parent
                        emitRate: 0
                        lifeSpan: 700
                        velocity: AngleDirection {angleVariation: 360; magnitude: 80; magnitudeVariation: 40}
                        size: 16
                    }
                }
    
                states: [
                    State {
                        name: "AliveState"
                        when: spawned == true && dying == false
                        PropertyChanges { target: img; opacity: 1 }
                    },
    
                    State {
                        name: "DeathState"
                        when: dying == true
                        StateChangeScript { script: particles.burst(50); }
                        PropertyChanges { target: img; opacity: 0 }
                        StateChangeScript { script: block.destroy(1000); }
                    }
                ]
            }
        }
    }
    

Get a Free Qt Trial

Like this and ready for the full-blown Qt experience?
Evaluate the Qt framework, tools for desktop and embedded development on MCUs and MPUs, plus other enterprise add-ons. If you are a UI designer, you should definitely try out Qt Design Studio also available in the evaluation package.

 
Download free trial


Rather book a meeting for a live technical demo?

 
Request meeting





* Beta version due to Qt Web Assembly feature development