Author: Lao Jiu – technology big millet

Socializing: Zhihu

Public account: Lao Jiu School (Surprise for newcomers)

Special statement: the original is not easy, without authorization shall not be reproduced or copied, if you need to reproduce can contact the author authorized

preface

This handout code is implemented using Qt 6 version, please rest assured to use.

What is the QML

Let me translate it for you.

QML is an abbreviation of Qt Meta-Object Language. It is a declarative programming language, and it is part of the Qt framework. The main function of QML is to allow developers to quickly and easily develop user interfaces for desktop applications, mobile devices, and embedded applications. Moreover, QML can be developed and used seamlessly with JavaScript, meaning that JavaScript files can be used directly within QML code.

The first Hello World

import QtQuick 2.9
import QtQuick.Window 2.2

Window{
    visible:true
    width:640
    height:480
    title:qsTr("Hell World");

    Rectangle {
        width: 360
        height: 360
        Rectangle{
            id: button1

            width: 100
            height: 30
            color: "red"
            radius: 5
            anchors.centerIn:parent

            Text{
                id: buttonText
                text:qsTr("Button")
                color:"white"
                anchors.centerIn:parent
            }

            MouseArea{
                anchors.fill:parent
                onClicked:{
                    buttonText.text = qsTr("Clicked");
                    buttonText.color = "black";
                }
            }
        }
    }

    Text{
        id:text1
        text: qsTr("Hello World")
        anchors.left:button1.right
    }

    Image{
        source:"nb.png"
        anchors.centerIn:parent
    }
}
Copy the code

Running effect

Mouse event response

import QtQuick 2.9
import QtQuick.Window 2.2

Window{
    visible:true
    width:480
    height:240
    Rectangle{
        anchors.fill:parent
        color:"#4b7a4a"
        MouseArea{
            anchors.fill:parent
            acceptedButtons: Qt.AllButtons
            onClicked: {console.log("Mouse Clicked.")
                console.log("Mouse Location: <",mouseX,",",mouseY,">").
                if ( mouse.button === Qt.RightButton )
                parent.color = 'blue'
                if ( mouse.button === Qt.LeftButton )
                parent.color = 'red'
                if ( mouse.button === Qt.MiddleButton )
                parent.color = 'yellow'
            }
            onReleased: {
                // print to console
                console.log("Mouse Released.")}onDoubleClicked: {
                // print to console
                console.log("Mouse Double Clicked.")}}}}Copy the code

Running effect

animation

Demo code

import QtQuick 2.9
import QtQuick.Window 2.2

Window{
    visible: true
    width: 400
    height: 640
    Rectangle{
        id: rect
        anchors.centerIn: parent
        height: 100
        width: 100
        color: "blue"
        MouseArea{
            anchors.fill: parent
            onClicked: na.running = true
        }
        NumberAnimation {
            id: na // The ID of the animation type
            target: rect // The target item for the animation to run
            property: "height" // What are the attributes of the target item for animation modification
            duration: 200 // The length of animation execution time
            from: rect.height // The initial value of the animation property
            to: 200 // The final value of the property after animation execution}}}Copy the code

Running effect

We click on the blue square

Create custom elements in C++

QML has a large number of visual elements, and it is possible to build complex applications with QML visual elements if you only use the QML scripting language. We can build interfaces based on these standard widgets, and we can also use Canvas elements to create custom elements. All QML interface elements can be constructed, except for touch elements.

However, QML scripts are not a panacea, although QML can be used to implement two types of custom drawing elements because of OpenGL technology:

  • The traditional for Qt way using QPainter (QQuickPaintedItem). (The traditional way is to use QPainter/QQuickPaintedItem to map interface)
  • The common QML way using QQuickItem and OpenGL functionality. The common QML way using QQuickItem and OpenGL functionality.

The first approach seems easy to implement, and QtQuick is slow to draw efficiently, so interface elements run faster if we use the second approach.

Demo code

QQuickCustomItem header file

#pragma once
#include <QQuickItem>
/** * create a custom class that implements the QQuickItem class. Used to demonstrate the implementation of custom control elements
class QQuickCustomItem :
    public QQuickItem
{
	Q_OBJECT
	Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
public:
	QQuickCustomItem(QQuickItem* parent = Q_NULLPTR);

	void paint(QPainter* painter);
protected:
	QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData);
	QColor color(a) const;
	void setColor(const QColor& color);
private:
	QColor m_color;
	bool m_needUpdate;

signals:
	void colorChanged(a);
};
Copy the code

QQuickCustomItem source file

#include "QQuickCustomItem.h"
#include <QSGGeometryNode>
#include <QSGFlatColorMaterial>
#include <QPainterPath>
#include <QPainter>

QQuickCustomItem::QQuickCustomItem(QQuickItem* parent /*= Q_NULLPTR*/)
	:QQuickItem(parent),
	m_color(Qt::red),
	m_needUpdate(true)
{
	setFlag(QQuickItem::ItemHasContents);
}


void QQuickCustomItem::paint(QPainter* painter)
{
	QPainterPath path;
	path.moveTo(width(a) /2.0);
	path.lineTo(width(), height());
	path.lineTo(0.height());
	path.lineTo(width(a) /2.0);
	painter->fillPath(path, m_color);
}

QSGNode* QQuickCustomItem::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData)
{
	Q_UNUSED(updatePaintNodeData)
		QSGGeometryNode* root = static_cast<QSGGeometryNode*>(oldNode);
	if(! root) { root =new QSGGeometryNode;
		QSGGeometry* geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 3);
		geometry->setDrawingMode(6);
		geometry->vertexDataAsPoint2D(to)0].set(width(a) /2.0);
		geometry->vertexDataAsPoint2D(to)1].set(width(), height());
		geometry->vertexDataAsPoint2D(to)2].set(0.height());
		root->setGeometry(geometry);
		root->setFlag(QSGNode::OwnsGeometry);
		root->setFlag(QSGNode::OwnsMaterial);
	}
	if (m_needUpdate) {
		QSGFlatColorMaterial* material = new QSGFlatColorMaterial;
		material->setColor(m_color);
		root->setMaterial(material);
		m_needUpdate = false;
	}
	return root;
}

QColor QQuickCustomItem::color(a) const
{
	return m_color;
}

void QQuickCustomItem::setColor(const QColor& color)
{
	if(m_color ! = color) { m_color = color; m_needUpdate =true;
		update(a);colorChanged();
	}
}
Copy the code

The main QML file

import QtQuick 2.3
import QtQuick.Window 2.2
import main.qml 1.0

Window {
    width: 800
    height: 800
    visible: true
    Rectangle {
        width: 200
        height: 200
        anchors.centerIn: parent
        color: "lightgrey"
        Triangle {
            id: rect
            width: 200
            height: 200
            transformOrigin: Item.Top
            color: "green"
            onColorChanged: console.log("color was changed");
            PropertyAnimation on rotation {
                from: 0
                to: 360
                duration: 5000
                loops: Animation.Infinite
            }
        }
    }
    Timer {
        interval: 1000
        repeat: true
        running: true
        onTriggered: rect.color = Qt.rgba(Math.random(),Math.random(),Math.random(),1); }}Copy the code

The main CPP file

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "QQuickCustomItem.h"

int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QGuiApplication app(argc, argv);

    // Technology: use custom components to display triangle animation
	qmlRegisterType<QQuickCustomItem>("main.qml".1.0."Triangle");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return - 1;

    return app.exec(a); }Copy the code

Running effect

With c + + integration

We can create QtQuick views directly from C++, and we can also expose C++ defined functions to QML.

The main CPP file

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "QQuickCustomItem.h"
#include <QQuickView>
#include <QQmlContext>

int main(int argc, char *argv[])
{#if defined(Q_OS_WIN)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QGuiApplication app(argc, argv);
    
	QQuickView view;
	view.setSource(QStringLiteral("main.qml"));
	// Retrieving the QML context. This context allows us to expose data to the QML components
	QQmlContext* rootContext = view.rootContext();
	// Creating 2 new properties: the width and height of the view
	rootContext->setContextProperty("WINDOW_WIDTH".640);
	rootContext->setContextProperty("WINDOW_HEIGHT".360);
	// Let's display the view
	view.show();

    return app.exec();
}

Copy the code

The main QML file

import QtQuick 2.3

Rectangle {
    // We can now access the properties we defined from C++ from the whole QML file
    width: WINDOW_WIDTH
    height: WINDOW_HEIGHT
    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
}
Copy the code

Running effect

Qt5 version updated

For qT5.x, we can replace the QQuickView class with the QQmlApplicationEngine class to load and render QML scripts. Modify the code as follows:

Modify the main CPP

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "QQuickCustomItem.h"
#include <QQuickView>
#include <QQmlContext>

int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QGuiApplication app(argc, argv);

	QQmlApplicationEngine engine;
	QQmlContext* rootContext = engine.rootContext(a); rootContext->setContextProperty("WINDOW_WIDTH".640);
	rootContext->setContextProperty("WINDOW_HEIGHT".360);
	engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec(a); }Copy the code

Modify the main QML

import QtQuick 2.3
import QtQuick.Window 2.2

Window { // Must be this type to be loaded by QQmlApplicationEngine.
    visible: true
    width: WINDOW_WIDTH //Accessing global context declared in C++
    height: WINDOW_HEIGHT //Accessing global context declared in C++
    title: qsTr("Hello World")
    Component.onCompleted: {
        // We can access global context from within JavaScript too.
        console.debug( "Width: " + WINDOW_WIDTH )
        console.debug( "Height: " + WINDOW_HEIGHT )
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }
    Text {
        text: qsTr("Hello World! and click here to quit the programm.")
        anchors.centerIn: parent
    }
}
Copy the code

Running effect

The last

Remember to give dashu ❤️ attention + like + collect + comment + forward ❤️

Author: Lao Jiu School – technology big millet

Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.