QML与C++成员变量、成员方法、信号之间的互操作

目录

1,效果演示:

2,概述:

3,暴露变量:用 Q_PROPERTY() 宏,将成员变量导出为Qt属性,并允许QML属性绑定:

4,暴露方法:用 Q_INVOKABLE 宏:

5,暴露信号:

6,实战:测试平台:Qt 5.15.0  MinGW 32-bit:


  1. 参考博客:https://blog.csdn.net/weixin_37459951/article/details/72901831
  2. 参考博客:https://blog.csdn.net/qq_34139994/article/details/105195328
  3. 参考博客:https://blog.csdn.net/taohe_0/article/details/51353311
  4. 参考博客:https://www.cnblogs.com/itrena/p/5938245.html

1,效果演示:

2,概述:

这里主要学习,如何将C++类的:成员变量、成员方法、信号,暴露给 QML。达到QML与C++的互操作的目的。
参考资料:《Qt 官方文档》, 章节:The Property System  个别地方引用了官方原文。

3,暴露变量:用 Q_PROPERTY() 宏,将成员变量导出为Qt属性,并允许QML属性绑定:

 在继承 QObject 的类中,使用 Q_PROPERTY() 宏声明属性。Q_PROPERTY() 语法:

Q_PROPERTY(type name
            (READ getFunction [WRITE setFunction] |
             MEMBER memberName [(READ getFunction | WRITE setFunction)])
            [RESET resetFunction]
            [NOTIFY notifySignal]
            [REVISION int]
            [DESIGNABLE bool]
            [SCRIPTABLE bool]
            [STORED bool]
            [USER bool]
            [CONSTANT]
            [FINAL])
            [REQUIRED]

The property name and type and the READ function are required. The type can be any type supported by QVariant, or it can be a user-defined type. The other items are optional, but a WRITE function is common. The attributes default to true except USER, which defaults to false. ——(Qt 官方文档)译:【属性的 name 、type 、READ函数 是必需的。属性的类型可以是QVariant支持的任何类型,也可以是用户定义的类型。其他项是可选的,但是WRITE函数也很常用。除了USER属性,其他属性默认为真。】

READ funcR:定义了读取属性的接口funcRfuncRconst类型,返回值类型为属性类型,不能带参数。
WRITE funcW:定义了设置属性的接口funcWfuncW必须带有一个属性类型的参数,返回值类型void
MEMBER varMEMBER指明了成员变量var即可读也可写的,相当于同时使用了READWRITE关键字。不同的是,READWRITE关键字通过类的接口来实现,而MEMBER关键字是通过类的对象直接访问来实现的。
 Note that a NOTIFY signal must be specified to allow QML property bindings.  注意,必须指定一个 NOTIFY 信号来允许QML属性绑定 

    ...
    Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged)

signals:
    void textChanged(const QString &newText);

private:
    QString m_text;
    ...

4,暴露方法:用 Q_INVOKABLE 宏:

通过以下两种方式把类方法暴露到QML。如果C++方法有QObject类型的参数时,在QML中使用对象ID或var类型参数来进行参数传递。
        (1)使用宏 Q_INVOKABLE 宏标记公共方法。
        (2)把方法声明为public槽函数 public slots,(声明为protected槽函数 protected slots。测试了一下,也可行)

5,暴露信号:

信号无需特殊处理。将类或类的对象成功注册到在QML后,可直接使用。使用方法:(以注册对象为例)
testObj.refreshTime.connect(refreshCurrentTime)
testObj: 注册到QML的对象名
refreshTime: testObj对象的时间刷新信号
refreshCurrentTime: qml中定义的refreshTime信号处理函数

6,实战:测试平台:Qt 5.15.0  MinGW 32-bit:

使用方法:将类或类的对象注册到QML。

例子:注册过程在 main() 中完成:==>>【 有关如何导入C++类或对象,看这里!!! 

完整工程下载:【直达电梯 ... QML与C++对象间的互操作:工程Demo

完整代码如下:

main().cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQuick>
#include "myclass.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);  //窗体尺寸变化时防闪屏
    QQuickWindow::setTextRenderType(QQuickWindow::NativeTextRendering);  //本地字体

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    // 注册 C++ 对象
    MyClass testObj;
    engine.rootContext()->setContextProperty("testObj", &testObj);

    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);

    // logo
    app.setWindowIcon(QIcon(":/image/logo.png"));
    return app.exec();
}

myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QString>
#include <QTimer>

class MyClass : public QObject
{
    Q_OBJECT

    // 使用 MEMBER 关键字
    Q_PROPERTY(int age MEMBER m_nAge NOTIFY ageChanged)
    Q_PROPERTY(QString name MEMBER m_strName NOTIFY nameChanged)

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

    Q_INVOKABLE void testFunc01();
    void testFunc03();

public slots:
    void testFunc02();

private:
    void getCurrentTime();

signals:
    void ageChanged();
    void nameChanged(const QString &newName);

    //普通信号
    void refreshTime(const QString time);
private:
    QString m_strName;
    int m_nAge;

    QTimer m_timer;
};

#endif // MYCLASS_H

 myclass.cpp

#include "myclass.h"
#include <QDateTime>
#include <QString>
#include <QDebug>

MyClass::MyClass(QObject *parent) : QObject(parent){
    this->m_strName = "悟空";
    this->m_nAge = 18;

    connect(&m_timer, &QTimer::timeout, this, &MyClass::getCurrentTime);
    this->m_timer.start(1000);  //启动定时器
}

void MyClass::testFunc01(){
    qDebug()<<"Q_INVOKABLE 声明的公有方法 ...";
}

void MyClass::testFunc02(){
    qDebug()<<"public 槽函数 ...";
}

void MyClass::testFunc03(){
    qDebug()<<"普通公有方法 ...";
}

void MyClass::getCurrentTime(){
    QString currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    this->refreshTime(currentTime);
}

 main.qml

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15

Window {
    id: root
    width: 360; height: 400
    visible: true
    title: qsTr("QML And C++ Class ...")
    color: "#E6E6FA"

    Column {
        x: (root.width-width)/2
        y: 10
        spacing: 5

        MyLabel {
            id: nameLabel
        }

        MyLabel {
            id: ageLabel
        }

        MyLabel {
            id: timeLabel
        }

        Button {
            id: btn01
            width: 260
            highlighted: true
            text: "Q_INVOKABLE 声明的公有方法"

            onClicked: testObj.testFunc01()
        }
        Button {
            id: btn02
            width: 260
            highlighted: true
            text: "public slots 公有槽函数"

            onClicked: testObj.testFunc02()
        }
    }

    function refreshCurrentTime(strTime){
        timeLabel.text = strTime
    }

    function changeName(){
        nameLabel.text = testObj.name
    }

    function changeAge(){
        ageLabel.text = testObj.age
    }

    Component.onCompleted: {
        testObj.refreshTime.connect(refreshCurrentTime)
        testObj.onNameChanged.connect(changeName)
        testObj.onAgeChanged.connect(changeAge)

        nameLabel.text = qsTr(testObj.name)
        ageLabel.text = qsTr(String(testObj.age))
    }

    /** 辅助测试控件 *********************************/
    Text {
        id: log
        text: qsTr("这里显示错误信息")
        x: testInfo.x
        anchors.bottom: testInfo.top
        anchors.bottomMargin: 5
    }

    TestSeting{
        id: testInfo
        x: (root.width-width)/2
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 10
    }
}

 MyLabel.qml

import QtQuick 2.15
import QtQuick.Controls 2.15

Rectangle {
    width: 260; height: 30
    color: "#606060"
    border.color: "#303030"

    property alias text: info.text

    Text {
        id: info
        text: qsTr("MyLabel")
        font.pixelSize: 24
        color: "#00FFFF"

        anchors.centerIn: parent
    }

}

TestSeting.qml

import QtQuick 2.15
import QtQuick.Controls 2.15

Rectangle {
    id: root
    width: 260; height: 100
    border.color: "gray"

    Grid {
        id: layout
        columns: 2
        spacing: 5
        anchors.centerIn: root

        // 修改testObj 的 m_strName 属性
        Text {
            width: 100; height: 25
            text: qsTr("修改 m_strName:")
            verticalAlignment: Text.AlignVCenter
        }


        TextField {
            width: 120; height: 25

            text: "悟空"
            background: Rectangle{
                color: "#FFE0E0"
                border.color: "black"
            }
            onTextChanged: { testObj.name = text }
        }


        // 修改testObj 的 m_nAge 属性
        Text {
            width: 100; height: 25
            text: qsTr("修改 m_nAge:")
            verticalAlignment: Text.AlignVCenter
        }

        TextField {
            width: 120; height: 25
            text: "18"
            background: Rectangle{
                color: "#FFE0E0"
                border.color: "black"
            }

            onTextChanged: {
                var age = Number(text)
                if(isNaN(age))
                    log.text = "m_aAge 数值无效 ..."
                else{
                    testObj.age = age
                    log.text = "这里显示错误信息"
                }
            }
        }
    }
}

 

 

 

 

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QML 中访问 C++ 单例成员变量也很简单,只需要在 C++ 中添加对应的 Q_PROPERTY,并在 QML 中将单例绑定到一个对象上即可。 例如,如果想在 QML 中访问名为 `myProperty` 的成员变量,可以在 MySingleton 中添加以下代码: ```cpp class MySingleton : public QObject { Q_OBJECT Q_PROPERTY(int myProperty READ myProperty WRITE setMyProperty NOTIFY myPropertyChanged) public: static MySingleton* instance() { static MySingleton* instance = new MySingleton(); return instance; } int myProperty() const { return m_myProperty; } void setMyProperty(int value) { if (value != m_myProperty) { m_myProperty = value; emit myPropertyChanged(); } } signals: void mySignal(); void myPropertyChanged(); private: MySingleton() {} int m_myProperty; }; ``` 然后在 main.cpp 中注册 QML 型: ```cpp qmlRegisterSingletonType<MySingleton>("com.example", 1, 0, "MySingleton", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return MySingleton::instance(); }); ``` 最后在 QML 中绑定对象并访问成员变量: ```qml import com.example 1.0 Item { MySingleton { id: mySingleton } Text { text: "My property: " + mySingleton.myProperty } Button { text: "Set property" onClicked: { mySingleton.myProperty = 42 } } } ``` 这样就可以在 QML 中访问 C++ 单例成员变量了。注意,需要在 QML 中使用 `MySingleton {}` 创建一个对象,并将其绑定到一个 ID 上,才能访问其成员变量

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值