zoukankan      html  css  js  c++  java
  • 【QML与C++混合编程】在 C++ 使用 QML 对象

    上两篇看过了如何在 QML 中使用 C++ 类型或对象,现在来看如何在 C++ 中使用 QML 对象。

    官方文档说,所有 QML 对象类型都是源自 QObject 类型,无论它们是由引擎内部实现还是第三方定义。这意味着 QML 引擎可以使用 Qt 元对象系统动态实例化任何 QML 对象类型并检查创建的对象。

    这对于从 C++ 代码创建 QML 对象非常有用,无论是显示可以直观呈现的 QML 对象,还是将非可视 QML 对象数据集成到 C++ 应用程序中。一旦创建了 QML 对象,就可以从 C++ 中检查它,以便读取和写入属性,调用方法和接收信号通知。

    可以使用 QQmlComponentQQuickView 来加载 QML 文档。QQmlComponent 将 QML 文档作为为一个 C++ 对象加载,然后可以从 C++ 代码进行修改。QQuickView 也可以这样做,但由于 QQuickView 是一个基于 QWindow 的派生类,加载的对象也将可视化显示,QQuickView 通常用于将一个可视化的 QML 对象集成到应用程序的用户界面中。

    一、代码

    下面通过代码来演示。

    Widget.h:

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    #include <QObject>
    #include <QQuickView>
    #include <QQuickItem>
    #include <QMetaObject>
    #include <QQmlProperty>
    #include <QDebug>
    
    namespace Ui {
    class Widget;
    }
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Widget(QWidget *parent = nullptr);
        ~Widget();
    
    signals:
        // 信号 --用来触发qml的函数
        // 注意参数为var类型,对应qml中js函数的参数类型
        void cppSendMsg(const QVariant &arg1,const QVariant &arg2);
    
    public slots:
        // 槽函数 --用来接收qml的信号
        void cppRecvMsg(const QString &arg1,const QString &arg2);
    
    private slots:
        void on_pushButton_clicked();
    
    private:
        Ui::Widget *ui;
    
        QQuickView *view;
    };
    
    #endif // WIDGET_H
    

    Widget.cpp:

    #include "widget.h"
    #include "ui_widget.h"
    
    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        view = new QQuickView;
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    void Widget::on_pushButton_clicked()
    {
        //【1】使用QQuickView的C++代码加载QML文档,显示QML界面
        // 另外可以用QQmlComponent、QQuickWidget加载QML文档 【QQuickView不能用Window做根元素】
        view->setSource(QUrl("qrc:/main.qml"));
        view->show();
    
        /* 文档如是说:
        应该始终使用QObject::setProperty()、QQmlProperty
        或QMetaProperty::write()来改变QML的属性值,以确保QML引擎感知属性的变化。*/
    
        //【2】通过QObject设置属性值、获取属性值
        QObject *qmlObj = view->rootObject(); // 获取到qml根对象的指针
        //qmlObj->setProperty("height",300);
        QQmlProperty(qmlObj, "height").write(300);
        qDebug() << "Cpp get qml property height" << qmlObj->property("height");
        // 任何属性都可以通过C++访问
        qDebug() << "Cpp get qml property msg" << qmlObj->property("msg");
    
        //【3】通过QQuickItem设置属性值、获取属性值
        QQuickItem *item = qobject_cast<QQuickItem*>(qmlObj);
        item->setWidth(300);
        qDebug() << "Cpp get qml property width" << item->width();
    
        //【4】通过objectName访问加载的QML子对象
        // QObject::findChildren()可用于查找具有匹配objectName属性的子项
        QObject *qmlRect = qmlObj->findChild<QObject*>("rect");
        if(qmlRect) {
            qmlRect->setProperty("color", "red");
            qDebug() << "Cpp get rect color" << qmlRect->property("color");
        }
    
        //【5】调用QML方法
        QVariant val_return;  // 返回值
        QVariant val_arg = "GongJianBo";  // 参数值
        // Q_RETURN_ARG()和Q_Arg()参数必须制定为QVariant类型
        QMetaObject::invokeMethod(qmlObj,
                                  "qml_method",
                                  Q_RETURN_ARG(QVariant,val_return),
                                  Q_ARG(QVariant,val_arg));
        qDebug()<<"QMetaObject::invokeMethod result"<<val_return; // qml函数中返回“ok”
    
        //【6】关联信号槽
        // 1.关联qml信号与cpp槽,如果信号参数为QML对象类型,信号用var参数类型,槽用QVariant类型接收
        QObject::connect(qmlObj, SIGNAL(qmlSendMsg(QString,QString)),
                         this, SLOT(cppRecvMsg(QString,QString)));
        // 2.关联cpp信号与qml槽
        // qml中js函数参数为var类型,信号也用QVariant类型
        QObject::connect(this, SIGNAL(cppSendMsg(QVariant,QVariant)),
                         qmlObj, SLOT(qmlRecvMsg(QVariant,QVariant)));
        // 此外,cpp信号也可以关联qml信号
    }
    
    void Widget::cppRecvMsg(const QString &arg1,const QString &arg2)
    {
        qDebug() << "CppObject::cppRecvMsg" << arg1 << arg2;
        qDebug() << "emit cppSendMsg";
        emit cppSendMsg(arg1,arg2);
    }
    

    main.qml:

    import QtQuick 2.9
    
    Item{
        id: root
         250
        height: 250
        // 自定义属性  --cpp可以访问
        property string msg: "fengMisaka"
        // 自定义信号  --可以触发cpp槽函数
        signal qmlSendMsg(string arg1,string arg2)
    
        // QML中的方法可以被cpp调用,也可以作为槽函数
        function qml_method(val_arg) {
            console.log("qml method runing", val_arg, "return ok")
            return "ok"
        }
        // 注意槽函数参数为var类型
        function qmlRecvMsg(arg1,arg2) {
            console.log("qml slot runing",arg1,arg2)
        }
    
        Rectangle {
            anchors.fill: parent
            color: "green"
            objectName: "rect" // 用于cpp查找对象
        }
    
        MouseArea {
            anchors.fill: parent
            onClicked: {
                console.log("qml 点击鼠标, 发送信号 qmlSendMsg")
                root.qmlSendMsg(root.msg, "myarg2")
            }
        }
    
        onHeightChanged: console.log("qml height changed")
        onWidthChanged: console.log("qml width changed")
    }
    

    效果如下图所示:

    二、下载链接

    GitHub下载链接:https://github.com/confidentFeng/QML_Demo/tree/master/CppCallQml


    参考:

    《Qt Quick核心编程》第11章

    QML与C++交互

    在 C++ 中, 怎么和 QML 对象交互 ?


  • 相关阅读:
    Leetcode Excel Sheet Column Number
    AlgorithmsI PA2: Randomized Queues and Deques Subset
    AlgorithmsI PA2: Randomized Queues and Deques RandomizedQueue
    AlgorithmsI PA2: Randomized Queues and Deques Deque
    AlgorithmsI Programming Assignment 1: PercolationStats.java
    hdu多校第四场 1003 (hdu6616) Divide the Stones 机智题
    hdu多校第四场 1007 (hdu6620) Just an Old Puzzle 逆序对
    hdu多校第四场1001 (hdu6614) AND Minimum Spanning Tree 签到
    hdu多校第三场 1007 (hdu6609) Find the answer 线段树
    hdu多校第三场 1006 (hdu6608) Fansblog Miller-Rabin素性检测
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/12208786.html
Copyright © 2011-2022 走看看