C++ 中如何访问 QML

Qt Quick 加载QML文档过程解析

先来看一下 Qt Quick 中常用的一些类的继承关系:

介绍几个重要的成员:

QQmlEngine

每个QML组件都在 QQmlContext 中实例化。QQmlContext 对于向QML组件传递数据至关重要。在QML中上下文按层次结构排列,此层次结构由 QQmlEngine 管理。在创建任何QML组件之前,应用程序必须已创建 QQmlEngine 才能访问QML上下文。

QQmlContext

上下文允许数据暴露给由QML引擎实例化的QML组件。每个 QQmlContext 都包含一组不同于其QObject属性的属性,这些属性允许按名称将数据显式绑定到上下文。通过调用 QQmlContext::setContextProperty() 来定义和更新上下文属性。

QQmlComponent

组件是可重用的、封装的QML类型,具有定义良好的接口。可以从QML文件创建QQmlComponent实例。

QQmlExpression

动态执行表达式 QQmlExpression, 允许客户端在C++中利用一个特定的QML上下文执行JavaScript表达式,表达式执行的结果以QVariant的形式返回,并且遵守QML引擎确定的转换规则。

QQuickWindow

QQuickWindow 提供与 QQuickItems 的场景交互和显示所需的图形场景管理。QQuickWindow总是有一个不可见的根项。若要将项添加到此窗口,请将项重新分配到根项或场景中的现有项。

QQuickView

这是QQuickWindow的一个子类,当给定主源文件的URL时,它将自动加载和显示QML场景。或者,您可以使用QQmlComponent实例化自己的对象,并将它们放置在手动设置的QQuickWindow中。

Qt Quick 加载一个 QML 对象的条件:

唯一的 一个 QQmlEngine 引擎用于加载QML文件;

唯一的 一个 QQmlContext 用于QML对象实例化和表达式执行的上下文环境;

一个 QQmlComponent 组件用于实例化第一个QML对象;

第一种加载方式:QQmlEngine + QQmlComponent

#include <QApplication>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQuickWindow>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QQmlEngine engine;
    QQmlComponent *component = new QQmlComponent(&engine);

    QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));

    component->loadUrl(QUrl("qrc:/main.qml"));

    if (!component->isReady() ) {
        qWarning("%s", qPrintable(component->errorString()));
        return -1;
    }

    QObject *topLevel = component->create();
    QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);

    QSurfaceFormat surfaceFormat = window->requestedFormat();
    window->setFormat(surfaceFormat);
    window->show();

    return app.exec();
}

使用 QQmlComponent 来实例化 QML 对象的注意事项:

要在 QQmlEngine 实例不可用的代码中创建组件实例,可以使用qmlContext() 或qmlEngine();

必须通过 component.create() 来创建实例;

创建完成之后需要把对象放入窗口下才能显示;

第二种加载方式:QQmlApplicationEngine + Window

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}


import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
}

QQmlApplicationEngine 是Qt中创建 Qt Quick 工程默认使用的引擎。

QQmlApplicationEngine 联合了 QQmlEngine 和 QmlComponent 去加载单独的QML文件,QQmlApplicationEngine 加载以 Window 为根对象的QML文档,QML文档拥有窗口的完整控制权。

第三种加载方式:QQuickView + Item

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQuickView *view = new QQuickView;
    view->setSource(QUrl("qrc:/main.qml"));
    view->show();
    return app.exec();
}


import QtQuick 2.12

Item {
    visible: true
    width: 640
    height: 480
}

不同于 QQmlApplicationEngine 的是,使用 QQuickView 显示QML文档,对窗口的控制权全部在C++代码。

C++中各种加载方式通过 object name 修改qml中的属性

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQuickWindow>
#include <QQuickView>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    // 1. 使用 QQmlApplicationEngine
//    QQmlApplicationEngine engine;
//    const QUrl url(QStringLiteral("qrc:/main.qml"));
//    engine.load(url);

//    QObject *rect = engine.rootObjects().at(0)->findChild<QObject*>("rect");
//    if (rect)
//        rect->setProperty("color", "red");



    // 2. 使用 QQmlEngine + QQmlComponent
//    QQmlEngine engine;
//    QQmlComponent *component = new QQmlComponent(&engine);
//    component->loadUrl(QUrl("qrc:/main.qml"));
//    QObject *topLevel = component->create();
//    QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
//    window->show();

//    QObject *rect = topLevel->findChild<QObject*>("rect");
//      if (rect)
//          rect->setProperty("color", "red");



    // 3. 使用 QQuickView
    QQuickView *view = new QQuickView;
    view->setSource(QUrl("qrc:/main.qml"));
    view->show();

    QObject *rect = view->findChild<QObject*>("rect");
    if (rect)
        rect->setProperty("color", "red");

    return app.exec();
}


import QtQuick 2.12
import QtQuick.Window 2.12

Item {
    visible: true
    width: 640
    height: 480

    Rectangle {
        objectName: "rect"
        anchors.fill: parent
        color: "yellow"
    }
}

Qt中的对象是一种树形的结构,对Qt对象树模型不了解的同学可以参考 Qt 对象树。所以我们只要知道了一个节点,就可以通过 findChild 来找到他的子节点。以上三种方式都可以通过 findChild 来找到object然后修改属性。前面两种方式,qml文件的根对象是Window,而最后一种是Item。

C++ 调用qml中的 function

import QtQuick 2.12

Item {
    function myQmlFunction(msg) {
        console.log("Got message:", msg)
        return "some return value"
    }
}


#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlEngine engine;
    QQmlComponent component(&engine, "qrc:/main.qml");
    QObject *object = component.create();

    QVariant returnedValue;
    QVariant msg = "Hello from C++";
    QMetaObject::invokeMethod(object, "myQmlFunction",
                              Q_RETURN_ARG(QVariant, returnedValue),
                              Q_ARG(QVariant, msg));

    qDebug() << "QML function returned:" << returnedValue.toString();
    delete object;

    return app.exec();
}

运行结果:
qml: Got message: Hello from C++
QML function returned: "some return value"

C++ 连接qml中的信号

myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QDebug>

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr);

signals:

public slots:
    void cppSlot(const QString &msg) {
        qDebug() << "Called the C++ slot with message:" << msg;
    }
};

#endif // MYCLASS_H
main.qml

import QtQuick 2.0

Item {
    width: 100; height: 100

    signal qmlSignal(string msg)

    MouseArea {
        anchors.fill: parent
        onClicked: qmlSignal("Hello from QML")
    }
}
main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <QQuickItem>
#include "myclass.h"

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

    QQuickView view(QUrl("qrc:/main.qml"));
    QObject *item = view.rootObject();

    MyClass myClass;
    QObject::connect(item, SIGNAL(qmlSignal(QString)),
                     &myClass, SLOT(cppSlot(QString)));

    view.show();
    return app.exec();
}

运行结果:
Called the C++ slot with message: "Hello from QML"

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

猜你喜欢

转载自blog.csdn.net/m0_73443478/article/details/129844458