QML与C++混合编程

2023-11-09

文章参考:
https://blog.csdn.net/foruok/article/details/32698603
http://blog.51cto.com/9291927/1975383

QT项目开发过程中,画面上显示的布局以及对应的数据可能会动态变化,如果只用QML来构件简单的布局是无法满足需求的,所以会用通过C++代码来实现业务逻辑,QML负责构件UI。这里用到MVC模式的思想。
QML与C++混合编程简介
QML与C++混合编程就是使用QML高效便捷地构建UI,而C++则用来实现业务逻辑和复杂算法。

Qt Quick与QML
Qt Quick是Qt User Interface Creation Kit的缩写。
QT框架简介中可以了解到,QML (Qt Meta-Object Language的缩写)其实是对 JavaScript 的扩展,是Qt Quick最重要的组成部分。
Qt Quick包含一个组件集合,大部分用于图形界面。同时也包含一个用于管理组件并与组件交互的C++ API——QtDeclarative模块,用于QML与C++之间的桥梁。
C++与QML的交互通过向QML注册C++对象实现,其中C++实现中,非可视化的类均为QObject的子类,可是化的类型均为QDeclarativeItem的子类,而QDeclarativeItem等同于QML的Item类。

QML 中使用 C++ 类和对象
Qt 提供了两种在 QML 环境中使用 C++ 对象的方式:

  1. 在 C++ 中实现一个类,注册到 QML 环境中, QML 环境中使用该类型创建对象;
  2. 在 C++ 中构造一个对象,将这个对象设置为 QML 的上下文属性,在 QML 环境中直接使用改属性.
    不管哪种方式,对要导出的 C++ 类都有要求,不是一个类的所有方法、变量都可以被 QML 使用,因此我们先来看看怎样让一个方法或属性可以被 QML 使用。

C++类的实现
C++类要想被QML访问,首先必须满足两个条件:

  1. 派生自QObject类或QObject类的子类;
  2. 二是使用Q_OBJECT宏。
    这两个条件跟QT信号和槽的实现一样,是为了让一个类能够进入 Qt 强大的元对象系统(meta-object system)中,只有使用元对象系统,一个类的某些方法或属性才可能通过字符串形式的名字来调用,才具有了在 QML 中访问的基础条件。

信号与槽实现
只要是信号或者槽,都可以在 QML 中访问。
信号在C++中使用时要用到emit关键字,但在QML中就是个普通的函数,用法同函数一样。

注册QML类型
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) 有两个模板函数:

template<typename T>
  int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);

  template<typename T, int metaObjectRevision>
  int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);

前一个原型一般用来注册一个新类型,而后一个可以为特定的版本注册类型。通常使用的是第一个,后面这个有兴趣可以自己详细了解。
参数含义:
typename :实现的 C++ 类的类名。
uri :让你指定一个唯一的包名,类似 Java 中的那种,一是用来避免名字冲突,而是可以把多个相关类聚合到一个包中方便引用。比如我们常写这个语句 “import QtQuick 1.0” ,其中的 “QtQuick” 就是包名 uri
versionMajor:指上述包名后面1.0中的“1”
versionMinor:指上述包名后面1.0中的“0”
qmlName : QML 中可以使用的类名。
例如:

qmlRegisterType<TestHuman >("qt.test.TestHuman", 1, 0, "TestHuman"); //只要保证在加载qml之前即可

当将C++类注册成功之后则可以在 QML 中创建 C++ 导入类型的对象了,与 QML 内建类型的使用完全一样。如下是创建一个 TestHuman 实例的代码:

import QtQuick 2.0
import qt.test.TestFlowers 1.0
Rectangle {
    width: 200;
    height: 200;
    
    TestFlowers {
        id: testflowers ;
        anchors.top: parent.top;
    }
	Button{
	id: testBtn1;
        text: qsTr("Hello World");
        anchors.top: testflowers .bottom;
        onClicked: {
                testHuman .onBtnClick();
            }
    }
}

上述qml文件可以看出C++对象可以跟其它部件使用完全一样,qml文件中通常要使用C++对象的成员属性、方法,为了能让C++的相关数据能被访问,则需要做特殊处理。

Q_PROPERTY
Q_PROPERTY 宏用来定义可通过元对象系统访问的属性,通过它定义的属性,可以在 QML 中访问、修改,也可以在属性变化时发射特定的信号。要想使用 Q_PROPERTY 宏,你的类必须是 QObject 的派生类,必须在类首使用 Q_OBJECT 宏。
下面是 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])

属性的type、name是必需的,其它是可选项,常用的有READ、WRITE、NOTIFY。属性的type可以是QVariant支持的任何类型,也可以是自定义类型,包括自定义类、列表类型、组属性等。

  • READ :如果你没有为属性指定 MEMBER 标记,则 READ 标记必不可少;声明一个读取属性的函数,该函数一般没有参数,返回定义的属性。
  • WRITE:可选配置。声明一个设定属性的函数。它指定的函数,只能有一个与属性类型匹配的参数,必须返回 void 。
    NOTIFY:可选配置。给属性关联一个信号(该信号必须是已经在类中声明过的),当属性的值发生变化时就会触发该信号。信号的参数,一般就是你定义的属性。

其它不常用的就不介绍了,感兴趣的可以查看SDK。

Q_ENUMS
如果你要导出的类定义了想在 QML 中使用枚举类型,可以使用 Q_ENUMS 宏将该枚举注册到元对象系统中。

Q_INVOKABLE
在定义一个类的成员函数时使用 Q_INVOKABLE 宏来修饰,就可以让该方法被元对象系统调用。这个宏必须放在返回类型前面。在 QML 中就可以用 O b j e c t . {Object}. Object.{method} 来访问。

代码:
C++类(.h文件):

class TestFlowers : public QObject
{
    Q_OBJECT
	Q_ENUMS(Color)
	Q_PROPERTY(Color color READ color WRITE setColor NOTIFY colorChange)
	Q_INVOKABLE void (onBtnClick)
public:
    TestFlowers (QObject *parent = 0);
    ~TestFlowers ();
	
	enum Color {
		RED,
		GREEN,
		BLUE
	};
    
};

qml:

import QtQuick 2.0
import qt.test.TestFlowers 1.0
Rectangle {
    width: 200;
    height: 200;
    
    TestFlowers {
        id: testflowers ;
        anchors.top: parent.top;
    }
	Button{
	id: testBtn1;
        text: qsTr("Hello World");
        anchors.top: testflowers .bottom;
        onClicked: {
                testflowers.onBtnClick();      //控件的点击事件,可以在类文件(.cpp)中实现业务逻辑
            }
    }
    Rectangle{
	id:background;
	width: parent.width;
	height:50;
	color:testflowers .color;        //可以直接使用C++属性值
	anchors.bottom: testBtn1.bottom;
	}
}

具体的C++类的.cpp文件就不详细写了,这里主要表达的是在qml中使用C++类的相关属性和方法。如果想在qml中使用C++类属性,则必须用特殊的宏才能使用。

注册C++ 对象为 QML 的属性
在C++应用程序加载QML对象时,可以直接嵌入一些C++数据来给QML使用,需要用到QQmlContext::setContextProperty()设置QML上下文属性,上下文属性可以是一个简单的类型,也可以是任何自定义的类对象。
以下代码在main函数中注册:

QtQuick2ApplicationViewer viewer;
viewer.rootContext()->setContextProperty("testflowers", new TestFlowers );  //这里new创建了对象,需要自己手动回收
viewer.setMainQmlFile(QStringLiteral("qml/testflowers/main.qml"));    //"qml/testflowers/main.qml"表示qml文件路径

通过上述方法注册之后。qml的使用有部分改动:

import QtQuick 2.0
// import qt.test.TestFlowers 1.0     已经注册,不需要了
Rectangle {
    width: 200;
    height: 200;
    
// 已经注册成属性了,不要了
/*    TestFlowers {
        id: testflowers ;
        anchors.top: parent.top;
    }*/
    
	Button{
	id: testBtn1;
        text: qsTr("Hello World");
        anchors.top: testflowers .bottom;
        onClicked: {
                testflowers.onBtnClick();      //控件的点击事件,可以在类文件(.cpp)中实现业务逻辑
            }
    }
    Rectangle{
	id:background;
	width: parent.width;
	height:50;
	color:testflowers .color;        //可以直接使用C++属性值
	anchors.bottom: testBtn1.bottom;
	}
}

在 C++ 中使用 QML 对象
在C++中也可以访问QML中的属性、函数和信号。QObject 类的构造函数有一个 parent 参数,可以指定一个对象的父亲, QML 中的对象其实借助这个组成了以根 item 为父的一棵对象树。
而 QObject 定义了一个属性 objectName ,这个对象名字属性,就可以用于查找对象。现在该说到查找对象的方法了: findChild() 和 findChildren() 。它们的函数原型如下:

T QObject::findChild(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
QList<T> QObject::findChildren(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const

用例:

QPushButton *button = parentWidget->findChild<QPushButton *>("button1");
QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>("widgetname");

在TestFlowers 类中查找testBtn1对象调用方法如下:
Button* button1 = this->findChild<Button*>(“testBtn1”);

PS:上述代码的实例没有写全,所以不要直接copy在实机上运行,上述相关方法都可以到QT SDK中找到,可以自己下载一个qt 工具,然后在里边搜索相关方法,里边都有详细介绍且非常方便(参考:QT框架简介里边的搜索方法)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QML与C++混合编程 的相关文章

  • Qt 的 Qss使用

    Qt 的 Qss 是一种用于定义用户界面的样式表语言 它可以用来定义控件的颜色 字体 边框 背景等样式 可以很方便的实现自定义的样式效果 Qss 的基本语法和 CSS 类似 主要是由选择器和样式属性构成 选择器 选择器用来指定要样式化的控件
  • qt学习笔记4:QMainWindow 菜单栏、工具栏、状态栏、铆接部件、

    在创建基类的时候 有三大选择 一个是QWidge 空窗口 另一个就是QMainWindow QMainWindow是一个为用户提供主窗口的类 包含一个菜单栏 多个工具栏 多个链接部件 一个状态栏以及一个中心部件 是许多应用程序的基础 如文本
  • QT读取文件夹下的特定文件

    话不多说 直接上代码 个人理解的注释 参考就行 1 选择目录 获取目录下文件的绝对路径 QString filepath QFileDialog getExistingDirectory this QStringLiteral 选择目录 F
  • QT学习——父窗口,信号和槽机制

    一 父窗口 容器窗口 1 概念 创建控件时可以指定停靠在父窗口上 如果没有指定 则飘在外面形成独立的窗体 父窗口本质也是图形控件 常用于表示父窗口类主要包括如下三个 QWidget QDialog 对话框 QMainWindow 主窗口 注
  • Qt 为.h和.cpp文件添加ui文件

    假设在工程中已经有了一个纯类A的头文件a h和源文件a cpp 现在想给这个纯类文件添加UI 可以通过以下操作来实现 给工程添加一个和类同名的UI文件a ui 在a cpp中添加UI的头文件 头文件的名字应该形如ui xxx h 但在添加时
  • Qt Creater Bug: multiple define of ...

    在导入自己写的文件到Qt 工程时 发现报了好多个 multiple define of 的错误 网上查了以下 解决方法有提到 头文件重复包含 ifndef define endif 编译出来的 o文件链接失败 需要clean工程的生成文件
  • Qt中的数据库(简单使用)

    在Qt中支持对数据库的操作 Qt中数据库的类有 驱动层 为具体的数据库和SQL接口层之间提供底层的桥梁 SQL层 提供对数据库的访问 QSqlDateBase类用来创建连接 QSqlQuery可以使用SQL语句实现交互 用户接口层 实现将数
  • Qt教程(2) : Qt元对象系统

    元对象是指用于描述另一个对象结构的对象 使用编程语言具体实现时 其实就是一个类的对象 只不过这个对象专门用于描述另一个对象而已 比如 class B class A B mb 假设 mb 是用来描述类 A 创建的对象的 则 mb 就是元对象
  • QT+VS配置及调试

    QT下载 https download qt io archive qt QT Creator设置 打开 Qt Creator 进入编译器部分 工具 gt 选项 gt 构建和运行 gt 编译器 可以看到vs的内容 之后 进入 工具 gt 选
  • QT学习-界面中实时绘制函数图像

    通过重写QT中QWidget类中的paintEvent函数 我们就可以做到在widget中进行函数图像的绘制 我使用的是QCreator的UI设计器 首先我们需要从QWidget继承一个子类 并重写他的paintEvent class sh
  • Qt学习之QMainWindow(一)QMainWindow简介

    详细的后续会讲到 这里重在理解过程 Qt中的顶层窗口称为MainWindow 属于类QMainWindow QMainWindow也是继承于QWidget 通过子类化QMainWindow可以创建一个应用程序的窗口 MainWindow的结
  • Ubuntu 18.04 安装Qt5.15.2开发环境

    1 下载Qt在线安装包 地址 Index of official releases online installers 选择Linux版本 右键复制链接地址 在Ubuntu终端 使用下载命令 wget 下载文件 wget https dow
  • QT---窗口、按钮的基本设置

    目录 一 窗口相关的设置及中文编译错误设置 1 在源文件widget cpp中进行修改数据 并创建有关界面 2 如遇中文编译错误 即标题中文显示乱码 可如下设置 3 窗口界面及标题设置 窗口是否拉伸 二 创建按钮的相关设置 1 添加头文件
  • QT基本使用

    目录 一 QWidget QDialog QMainWIndow的异同点 二 信号与槽 1 信号与槽 2 自动关联信号与槽 3 自定义信号与槽 设定槽 设定信号 四 模态 非模态窗口 1 新窗口的创建 2 模态 非模态窗口的创建 五 加载资
  • QT信号和槽的实现原理

    信号和槽是qt用于对象之间通信的核心机制 其目的类似于当一个动作发生的时候 需要对这个动作做出相应的处理 类似的还有借助于函数指针的回调机制 通过回调函数完成对此动作的操作 但是如果对一个庞杂的系统 这种回调函数的维护是相当的麻烦和危险的
  • Qt学习11:Dialog对话框操作总结

    文章首发于我的个人博客 欢迎大佬们来逛逛 完整Qt学习项目地址 源码地址 文章目录 QDialog QDialogButtonBox QMessageBox QFileDialog QFontDialog QColorDialog QInp
  • Qt 查看Qt助手的方法

    为了方便大家自学 在这里提供一种查看Qt助手的方法 1 打开软件点击帮助 在这里可以搜索关键词 2 假设搜索的是QToolBar 3 搜索的全是英文 这时可以点击 4 此时会跳到网页版Qt助手 5 使用的是 Microsoft Edge 浏
  • QT中的事件

    目录 1 QT事件 1 1 事件介绍 1 2 事件的处理 2 键盘事件 2 1 keyPressEvent 2 1 1 判断某个键按下 2 1 2 组合键操作 3 鼠标事件 3 1 鼠标单击事件 3 2 鼠标释放事件 3 3 鼠标双击事件
  • 使用QT纯代码创建(查找)对话框详细步骤与代码

    一 创建项目文件 打开Qt Creator gt 文件 gt 新建文件或项目 gt 选择Qt Widgets Application 为项目起名字 输入类的名字 二 了解每个文件的作用 项目创建完毕之后就会出现以下几个文件 先来分别介绍以下
  • 32位的Ubuntu16.04安装QT5.8,并编译实现window环境下的代码

    开始 这是本人的第一篇博客 自己经常在网上找问题的解决方法 发现有些问题很难找到合适的解决方法 所以自己也写写 希望能帮助到大家 有错的地方大家指出 安装环境 linux环境 Ubuntu16 04 32位系统 使用apt get命令进行安

随机推荐