Published on

How QML Works

Authors
  • avatar
    Name
    leejkee
    Twitter

QML的工作过程

纯QML Application

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: "Pure QML Application"

    Column {
        anchors.centerIn: parent
        spacing: 16

        Text {
            id: displayText
            text: "Hello, QML!"
            font.pixelSize: 24
            anchors.horizontalCenter: parent.horizontalCenter
        }

        Button {
            text: "Click Me"
            anchors.horizontalCenter: parent.horizontalCenter
            onClicked: {
                displayText.text = "Button Clicked!"
            }
        }
    }
}

QML With C++ Backend

使用MVVM架构简介

  • qml实现view,尽可能不包含任何业务逻辑,仅负责GUI显示和处理用户交互
  • 使用C++实现model,model类通常存储了数据在运行过程中的唯一副本,model要么提供直接操作数据的方式,要么实现操作数据的接口函数,它们会被viewmodel类调用
  • viewmodel应该完成处理用户请求的实现,viewmodel类中应该声明可供qml绑定的Q_PROPERTY属性,并按需要实现set和get函数
  • C++代码中需要将viewmodel类实例化的指针注册到qml的context中,由于MOC提供了反射机制,qml才可调用viewmodel类的函数

在C++代码中启动QML编写的窗口

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

class ViewModel : public QObject {
    Q_OBJECT
    Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged)

public:
    explicit ViewModel(QObject *parent = nullptr)
        : QObject(parent), m_message("Hello from C++!") {}

    QString message() const { return m_message; }

    void setMessage(const QString &msg) {
        if (m_message != msg) {
            m_message = msg;
            emit messageChanged();
        }
    }

    Q_INVOKABLE void updateMessage(const QString &newMsg) {
        setMessage(newMsg);
    }

signals:
    void messageChanged();

private:
    QString m_message;
};

int main(int argc, char *argv[]) {
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    ViewModel viewModel;
    engine.rootContext()->setContextProperty("viewModel", &viewModel);

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

    return app.exec();
}