QML与C++交互之创建自定义对象的实现

 更新时间:2025年07月07日 11:01:42   作者:cpp_learners  
本文介绍了在QML中通过C++定义全局对象的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在qml中,我们一般都是希望使用qml做界面展示,而数据处理转由c++处理;

在此篇博客,将介绍如何在c++中给qml定义全局对象;在c++中如何定义对象给qml使用。

1 给qml定义全局对象

正常我们定义了一个qml项目后,main函数是这样的:

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include <QQmlContext>

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

    QGuiApplication app(argc, argv);

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

    return app.exec();
}

QQmlApplicationEngine 是 Qt 框架中用于加载和运行基于 QML 的应用程序的核心类,结合了 QQmlEngine 和 QQmlComponent 的功能,支持从单个 QML 文件加载应用程序,并实现 C++ 与 QML 的双向通信。

那么,就可以使用QQmlApplicationEngine去获得全局上下文对象QQmlContext,通过使用上下文对象,就可以给qml设置一个全局的变量值;

获得上下文对象:

// 获得全局对象,上下文对象
QQmlContext *context = engine.rootContext();

给qml设置一个全局变量:

// 给qml设置一个全局变量;
context->setContextProperty("SCREEN_WIDTH", 800);

这样,就可以在qml中使用该变量了,例如在mian.qml文件内使用:

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.14

Window {
    id: root
    visible: true
    width: SCREEN_WIDTH    // 直接使用
    height: 500
    title: qsTr("Hello World")
    color: "white"

    // 如果qml内部有定义重名变量,那么会优先使用qml内部定义的变量,而不会使用C++定义的变量
    //property int SCREEN_WIDTH: 500
}

注意:如果qml内部有定义重名变量,那么会优先使用qml内部定义的变量;另外,定义全局变量会有性能消耗问题。

2 在c++中定义对象给qml使用

自定义C++类MyObject继承自QObject;有两个成员变量,int m_iValue 和 QString m_sString;并且给他俩定义get和set方法;另外在定义两个信号;最后通过Q_PROPERTY将两个成员变量暴露给元对象。

myobject.h

#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <QObject>

class MyObject : public QObject
{
    Q_OBJECT

public:
    MyObject(QObject *parent = nullptr);  // 构造函数
    ~MyObject();

    const int &iValue() const;
    void setIIValue(const int &newIValue);

    const QString &sString() const;
    void setSString(const QString &newSString);

signals:
    void iValueChanged();
    void sStringChanged();

private:
    int m_iValue;
    QString m_sString;

    Q_PROPERTY(int iValue READ iValue WRITE setIIValue NOTIFY iValueChanged)
//    Q_PROPERTY(QString sString READ sString WRITE setSString NOTIFY sStringChanged)
    // 如果值是函数内部成员变量的值,可使用MEMBER去设置,与READ sString WRITE setSString实现效果一致
    Q_PROPERTY(QString sString MEMBER m_sString NOTIFY sStringChanged)
};

#endif // MYOBJECT_H

myobject.cpp

#include "myobject.h"


MyObject::MyObject(QObject *parent) : QObject(parent)
{

}

MyObject::~MyObject()
{

}

const int &MyObject::iValue() const
{
    return m_iValue;
}

void MyObject::setIIValue(const int &newIValue)
{
    if (m_iValue == newIValue) {
        return;
    }

    m_iValue = newIValue;
    emit iValueChanged();
}

const QString &MyObject::sString() const
{
    return m_sString;
}

void MyObject::setSString(const QString &newSString)
{
    if (m_sString == newSString) {
        return;
    }

    m_sString = newSString;
    emit sStringChanged();
}

Q_PROPERTY的参数讲解

Q_PROPERTY(int iValue READ iValue WRITE setIIValue NOTIFY iValueChanged)

int iValue 指定是给qml使用的变量名,推荐与c++类成员变量名类似;

READ iValue 指的是通过iValue函数去读取值;

WRITE setIIValue 指的是通过setIIValue函数去修改iValue值;

NOTIFY iValueChanged 指的是当iValue值被修改后,会发送的信号;

然后main函数中使用qmlRegisterType函数对自定义类进行注册,注册后,就可以在qml那边导入使用了。

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include <QQmlContext>
#include "myobject.h"

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

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    // 获得全局对象,上下文对象
    QQmlContext *context = engine.rootContext();
    // 给qml设置一个全局变量;如果qml内部有定义重名变量,那么会优先使用qml内部定义的变量;另外,定义全局变量会有性能问题
    context->setContextProperty("SCREEN_WIDTH", 800);

    // 注册,在需要使用的地方 import MyObj 1.0
    qmlRegisterType<MyObject>("MyObj", 1, 0, "MyObject");

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

    return app.exec();
}

其中,MyObj是给qml那边导入时使用的模块名字,1 和 0 指的是版本,最后的MyObject就是自定义类名;

然后就可以在qml中 import MyObj 1.0 导入使用了。

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.14

import MyObj 1.0    // 导入自定义模块

Window {
    id: root
    visible: true
    width: SCREEN_WIDTH
    height: 500
    title: qsTr("Hello World")
    color: "white"


    MyObject {
        iValue: 20
        sString: "this is a custom obj.";

        Component.onCompleted: {
            console.log("iValue:", 20, "  sString:", sString)
        }
    }
}

3 番外

Q_PROPERTY为什么要指定NOTIFY信号呢?

在这里与qml的绑定有关系;

在qml中,当给一个变量以冒号':'方式赋值时,这两个变量是互相绑定的;例如:

property int testValue: myObj.iValue

当myObj.iValue被修改时,就会触发信号通知testValue也一并修改!

案例代码:定义变量testValue使用冒号被myObject.iValue赋值,定义按钮在onClicked槽函数中修改myObj.iValue值,观察testValue是否也被修改;

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.14

import MyObj 1.0    // 导入自定义模块

Window {
    id: root
    visible: true
    width: SCREEN_WIDTH
    height: 500
    title: qsTr("Hello World")
    color: "white"

    property int testValue: myObj.iValue    // 绑定了

    onTestValueChanged: {
        console.log("testValue:", testValue)
    }

    Button {
        width: 100; height: 50
        onClicked: {
           myObj.iValue = 50;
        }
    }

    MyObject {
        id: myObj

        iValue: 20
        sString: "this is a custom obj.";

        Component.onCompleted: {
            console.log("iValue:", 20, "  sString:", sString)
        }
    }
}

当点击按钮后,修改的是myObj.iValue,但testValue也一并被修改了,由此证明,使用冒号赋值时,他俩是会绑定在一起的。 

注意,使用 = 赋值时,不会有绑定的效果!!!

到此这篇关于QML与C++交互之创建自定义对象的实现的文章就介绍到这了,更多相关QML与C++交互内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C C++ 题解LeetCode2360图中的最长环示例

    C C++ 题解LeetCode2360图中的最长环示例

    这篇文章主要为大家介绍了C C++ 题解LeetCode2360图中的最长环示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • C++中的局部变量、全局变量、局部静态变量、全局静态变量的区别

    C++中的局部变量、全局变量、局部静态变量、全局静态变量的区别

    本文主要介绍了C++中的局部变量、全局变量、局部静态变量、全局静态变量的区别。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • C/C++中字符串的存储方式详解

    C/C++中字符串的存储方式详解

    在C语言中,字符串通常以字符数组的形式存在,并以空字符(\0)结尾,在C++中,建议使用 std::string 类来处理字符串,本文给大家介绍了C/C++中字符串的存储方式,需要的朋友可以参考下
    2024-11-11
  • C语言实现简单的<三子棋>案例

    C语言实现简单的<三子棋>案例

    这篇文章主要介绍了C语言实现简单的《三子棋》,本文通过功能区分一步步实现该案例,通过逐步的解析和代码列举,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C语言中的内存泄露 怎样避免与检测

    C语言中的内存泄露 怎样避免与检测

    堆经常会出现两种类型的问题:1.释放或改写仍在使用的内存(称为:“内存损坏”)。2.未释放不再使用的内存(称为:“内存泄露”)。这是最难被调试发现的问题之一
    2013-09-09
  • 浅析C++中cout的运行机制

    浅析C++中cout的运行机制

    关于C++中cout的使用,相信大家再熟悉不过了,然而对于cout是如何输出的?输出的机制是啥,需要进一步的了解。本章娓娓道来。前几天在网上看到这么一个题目
    2013-10-10
  • 最新C语言中getchar的使用

    最新C语言中getchar的使用

    getchar()是在输入缓冲区顺序读入一个字符(包括空格、回车和Tab) ,getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,本文给大家介绍getchar的使用,感兴趣的朋友跟随小编一起看看吧
    2022-12-12
  • C++实现恶搞电脑关机小程序的示例代码

    C++实现恶搞电脑关机小程序的示例代码

    这篇文章主要为大家详细介绍了如何利用C++实现一个简单的恶搞电脑关机小程序,文中的示例代码讲解详细,感兴趣的小伙伴可以尝试一下
    2022-11-11
  • c++ 基于opencv 识别、定位二维码

    c++ 基于opencv 识别、定位二维码

    这篇文章主要介绍了c++ 基于opencv 识别、定位二维码,帮助大家更好的理解和学习使用c++,感兴趣的朋友可以了解下
    2021-03-03
  • C语言PlaySound函数使用方法

    C语言PlaySound函数使用方法

    这篇文章介绍了C语言PlaySound函数的使用方法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-12-12

最新评论