zoukankan      html  css  js  c++  java
  • QML与Qt C++ 交互机制探讨与总结

    介绍

    QML和 C++对象可以通过,signals,slots和 属性修改进行交互。对于一个C++对象,任何数据都可以通过Qt的 Meta-Object System暴露给QML(何总方法,后面介绍),同时,任何的QML对象数据通过Meta-object system在C++端直接访问。
    在实际的项目中很多地方会用到QML与Qt C++交互。在这里总结了若干方法供大家参考,欢迎大家指导和拍砖。

    在这里不外乎有三种方法:
    1. 把Qt C++中的对象或类型暴露给 QML端,供QML端使用。(官方说法是“嵌入”而非“暴露”,比较文明。- -b)
    2. QML中的Signal Handler(相当于Qt C++发送信号给QML端,QML端的Signal Handler进行处理)。
    3. 在Qt C++端创建QML对象,既然对象都有了。那你想怎么样它就怎么样它呗。(没用过,看起来也不太实用,不过介绍介绍,有用过的同学留言哈)。

    好,我们开始吧~

    知识准备

    别急,让我们先来看看,一些东西,如果您都知道,可以跳过此节。
    QML API有三个主要成员——QDeclarativeEngineQDeclarativeComponentQDeclarativeContext

    QDeclarativeEngine提供了QML的运行环境。
    QDeclarativeComponent封装了QML Documents
    QDeclarativeContext允许程序使用QML组件显示数据。

    QML包含一个非常好用的API——QDeclarativeView。通过它,应用程序可以很方便的把QML组件嵌入到QGraphicsView中。QDeclarativeView主要用于在应用程序开发过程中进行快速原型开发。

    暴露Qt C++的对象或类型给QML

    创建需要暴露给QML的数据类型
    #ifndef MYCLASS_H
    #define MYCLASS_H
    #include <QObject>
    #include <QString>
    class MyClass : public QObject
    {
    Q_OBJECT
    Q_PROPERTY(QString myString READ myString WRITE setmyString NOTIFY myStringChanged)
    public:
    explicit MyClass(QObject *parent = 0);
    Q_INVOKABLE QString getMyString();
    signals:
    void myStringChanged();
    public slots:
    void setmyString(QString aString);
    QString myString();
    private:
    QString m_string;
    };
    #endif // MYCLASS_H

    若你想数据元素中的方法可以被QML直接调用有2种方法:
    1. 在函数申明前添加 Q_INVOKABLE 宏。
    2. 申明成public slots。

    QML可以直接访问改数据元素的属性,该属性由QPROPERTY所申明。
    具体实现请参考,示例代码。

    暴露已存在的Qt C++对象给QML
    //main.cpp
    MyClass myObj;
    QDeclarativeEngine *engine=viewer.engine();
    QDeclarativeContext *context=engine->rootContext();
    context->setContextProperty("myObjectExposeByCXProperty", &myObj);

    qml中可以直接使用myObjectExposeByCxProperty对象。

    //mainpage.qml
    ...
    Button{
    ...
    id:btn1
    ...
    text: qsTr("PROPERTY")
    //此处调用myString为MyClass的QPROPERTY的属性不是方法,所以没有括号。
    onClicked: label.text=myObjectExposeByCXProperty.myString;
    }
    ...
     
    
    
    注册Qt C++类类型给QML

    另外一种方式是注册类型
    //main.cpp
    qmlRegisterType<MyClass>("RegisterMyType", 1, 0, "MyClassType");

    QML中这样使用
    //mainpage.qml
    ...
    import RegisterMyType 1.0
    Button{
    id:btn2
    ...
    text: qsTr("INOVKABLE")
    //此处调用的时INVOKABLE的方法,不是属性,所以有括号。
    onClicked: label.text=myclassExposeByRegType.getMyString();
    }
    //创建对象,由于QML是解释执行的,所以放后面也没什么关系。
    MyClassType
    {
    id:myclassExposeByRegType
    }

    步骤:
    1. 导入import。
    2. 创建对象。
    3. id直接使用。

    QML中的Signal Handler


    还是使用上面的那例子,在qml中点击按钮控件,改变其中对象的字符串,这时候在Qt C++中发送一个signal信号给qml端,qml端接收到使用signal handler响应,改变label2的值。具体代码如下。
    qml中修改string的值。
    //mainpage.qml
    Button{
    id:btn3
    text: qsTr("emit stringchanged signal")
    onClicked: myObjectExposeByCXProperty.myString="xxxxx";
    }

    Qt C++触发信号
    //myclass.cpp
    void MyClass::setmyString(QString aString)
    {
    if(aString==m_string)
    {
    return;
    }
    m_string=aString;
    emit myStringChanged();
    }

    连接signal handler响应
    //mainpage.qml
    Connections
    {
    target: myObjectExposeByCXProperty
    onMyStringChanged:label2.text="Signal handler received"
    }

    有参数形式的:

    基本思路与具体步骤

    基本思路,把你的Qt C++中的对象暴露给QML端,然后利用signals-slots 进行连接,并传递消息。具体步骤如下
    1 创建自己的对象,如果你的对象是要显示在QML端,可以继承QDeclarativeItem,如果只是一个控制类,而不需要显示在QML端,只需要继承QObject。这里用到数据绑定请参考Using QML Bindings in C++ Applications

    #include<QObject>
    class NetConnectController : public QObject
    {
    Q_OBJECT
    Q_PROPERTY(int status READ status WRITE setStatus NOTIFY statusChanged) 
    public:
    explicit NetConnectController(QObject *parent = 0);
     
    void Ready()
    {
    emit statusChanged( m_status);
    }
    signals:
    void statusChanged(int aStatus);
    private:
    int status() const;
    void setStatus(int aStatus);
    private :
    //表示网络不同的状态
    int m_status;
    };


    2 暴露你的对象给QML

    ..... 
    NetConnectController netController
    QDeclarativeEngine * engine = viewer.engine();
    (engine->rootContext())->setContextProperty("NetController",&netController);
    .....

    3在QML中连接Signal-slot

    ......
     
    Connections
    {
    target: NetController
    onStatusChanged:changeStatus(aStatus)//Call JS Function
    }
    ......

    注意:上面的onStatusChanged 命名格式 “on”+"Qt C++中的signal名字"。在QML端可以直接使用Qt C++端的参数。例如上面的"aStatus"。

    
    

    Qt C++中直接调用QML的函数


    同样的QML的函数也可以被Qt C++端调用。
    所有的QML函数都通过meta-object system暴露Qt C++端,在Qt C++端可以使用QMetaObject::invokeMethod()方法直接调用。下面就是这样的一个例子。
    // MyItem.qml
    import QtQuick 1.0
    Item {
    function myQmlFunction(msg) {
    console.log("Got message:", msg)
    return "some return value"
    }
    }
    // main.cpp
    QDeclarativeEngine engine;
    QDeclarativeComponent component(&engine, "MyItem.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;

    注意:QMetaObject::invokeMethod()方法中的参数Q_RETURN_ARG()和Q_ARG()都被定义为QVariant类型,此类型是QML函数的的参数和返回值的通用数据类型。
    更多例程可以在SDK的安装目录中:QtSDKExamples4.7declarative utorialsextending 看到。
  • 相关阅读:
    正则表达式
    JavaScript基础
    Servlet监听器
    Java EKT关键技术强化 tomcat中文乱码问题
    spring和springmvc 整合步骤
    [ERROR] [ERROR] Some problems were encountered while processing the POMs: [ERROR] 'packaging' with value 'war' is invalid. Aggregator projects require 'pom' as packaging. @ line 9, column 16
    Pagehelper的 使用
    异步 json的使用
    分页技术 PageHelper
    Exception encountered during context initialization
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/6211142.html
Copyright © 2011-2022 走看看