首页 > 编程语言 >QML调用C++的三种方法

QML调用C++的三种方法

时间:2023-02-04 15:15:04浏览次数:61  
标签:调用 const int void C++ CppObject QML include

1.注册法
由于QML引擎与Qt元对象系统的紧密集成,可以从QML代码访问由QObject派生的类适当公开的任何功能。这使得C ++类的属性和方法可以直接从QML访问,通常很少或无需修改。

QML引擎能够通过元对象系统内省QObject实例。这意味着,任何QML代码都可以访问QObject派生类实例的以下成员:

属性(使用Q_PROPERTY注册的属性)
方法(需注册为public slots或是标记为Q_INVOKABLE)
信号
(此外,如果已使用Q_ENUMS声明枚举,则可以使用枚举。)

通常,无论是否已向QML类型系统注册了QObject派生类,都可以从QML访问它们。但是,如果QML引擎要访问其他类型信息(例如,如果要将类本身用作方法参数或属性,或者要将其中一个枚举类型用于以这种方式使用),那么该类可能需要注册。

#ifndef CPPOBJECT_H
#define CPPOBJECT_H

#include <QObject>

//派生自QObject
//使用qmlRegisterType注册到QML中
class CppObject : public QObject
{
Q_OBJECT
//注册属性,使之可以在QML中访问--具体语法百度Q_PROPERTY
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
Q_PROPERTY(int year READ getYear WRITE setYear NOTIFY yearChanged)

public:
explicit CppObject(QObject *parent = nullptr);
//通过Q_INVOKABLE宏标记的public函数可以在QML中访问
Q_INVOKABLE void sendSignal();//功能为发送信号

//给类属性添加访问方法--myName
void setName(const QString &name);
QString getName() const;
//给类属性添加访问方法--myYear
void setYear(int year);
int getYear() const;

signals:
//信号可以在QML中访问
void cppSignalA();//一个无参信号
void cppSignalB(const QString &str,int value);//一个带参数信号
void nameChanged(const QString name);
void yearChanged(int year);

public slots:
//public槽函数可以在QML中访问
void cppSlotA();//一个无参槽函数
void cppSlotB(const QString &str,int value);//一个带参数槽函数

private:
//类的属性
QString myName;
int myYear;
};

#endif // CPPOBJECT_H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
在头文件中,我定义了信号和public槽函数,以及Q_INVOKABLE宏标记的public函数,还通过Q_PROPERTY注册了两个属性,这些方法和属性之后都可以在QML中进行访问。

#include "CppObject.h"

#include <QDebug>

CppObject::CppObject(QObject *parent)
: QObject(parent),
myName("none"),
myYear(0)
{

}

void CppObject::sendSignal()
{
//测试用,调用该函数后发送信号
qDebug()<<"CppObject::sendSignal";
emit cppSignalA();
emit cppSignalB(myName,myYear);
}

void CppObject::setName(const QString &name)
{
qDebug()<<"CppObject::setName"<<name;
if(myName!=name){
qDebug()<<"emit nameChanged";
myName=name;
emit nameChanged(name);
}
}

QString CppObject::getName() const
{
qDebug()<<"CppObject::getName";
return myName;
}

void CppObject::setYear(int year)
{
qDebug()<<"CppObject::setYear"<<year;
if(year!=myYear){
qDebug()<<"emit yearChanged";
myYear=year;
emit yearChanged(myYear);
}
}

int CppObject::getYear() const
{
qDebug()<<"CppObject::getYear";
return myYear;
}

void CppObject::cppSlotA()
{
qDebug()<<"CppObject::cppSlotA";
}

void CppObject::cppSlotB(const QString &str, int value)
{
qDebug()<<"CppObject::cppSlotB"<<str<<value;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
在QML项目中添加类CppObject,并在QQmlApplicationEngine之前注册

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

单例
int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, QJSValue(* ) ( QQmlEngine *, QJSEngine * ) callback)
int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *(* ) ( QQmlEngine *, QJSEngine * ) callback)
int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
1
2
3
4
5
6
7
8
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "CppObject.h"

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

QGuiApplication app(argc, argv);

//qmlRegisterType注册C++类型至QML
//arg1:import时模块名
//arg2:主版本号
//arg3:次版本号
//arg4:QML类型名
qmlRegisterType<CppObject>("MyCppObject",1,0,"CppObject");

QQmlApplicationEngine engine;

//也可以注册为qml全局对象
//engine.rootContext()->setContextProperty("cppObj",new CppObject(qApp));

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

return app.exec();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
通过使用qmlRegisterType,将刚才定义的QObject派生类注册到QML中(Qt5.15增加了新的注册方式)。

import QtQuick 2.9
import QtQuick.Window 2.9
//引入我们注册的模块
import MyCppObject 1.0

Window {
id: root
visible: true
width: 500
height: 300
title: qsTr("QML调用Cpp对象")
color:"green"

signal qmlSignalA
signal qmlSignalB(string str,int value)

//鼠标点击区域
MouseArea{
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
//测试时点击左键或右键
onClicked: {
if(mouse.button===Qt.LeftButton){
console.log('----qml 点击左键:Cpp发射信号')
cpp_obj.name="CSDN" //修改属性会触发set函数,获取值会触发get函数
cpp_obj.year=2020
cpp_obj.sendSignal() //调用Q_INVOKABLE宏标记的函数
}else{
console.log('----qml 点击右键:QML发射信号')
root.qmlSignalA()
root.qmlSignalB('CSDN',2020)
}
}
}

//作为一个QML对象
CppObject{
id:cpp_obj
//也可以像原生QML对象一样操作,增加属性之类的
property int counts: 0
//值改变信号对应的槽函数,on + * 方式信号槽,自动连接
onYearChanged: {
counts++
console.log('qml onYearChanged',counts)
}
onCountsChanged: {
console.log('qml onCountsChanged',counts)
}
}

//组件加载完成执行
Component.onCompleted: {
//关联信号与信号处理函数的方式同QML中的类型
//Cpp对象的信号关联到Qml
//cpp_obj.onCppSignalA.connect(function(){console.log('qml signalA process')})
cpp_obj.onCppSignalA.connect(()=>console.log('qml signalA process')) //js的lambda
cpp_obj.onCppSignalB.connect(processB)
//Qml对象的信号关联到Cpp
root.onQmlSignalA.connect(cpp_obj.cppSlotA)
root.onQmlSignalB.connect(cpp_obj.cppSlotB)
}

//定义的函数可以作为槽函数
function processB(str,value){
console.log('qml function processB',str,value)
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
注册之后就能直接在QML中使用刚才定义的C++类型了,并且可以像QML定义的类型一样进行操作,如信号槽关联、属性绑定等

2.插件法
在Qt新项目向导下创建项目Library->Qt Quick 2 Extension Plugin
输入你的项目名称(此例为QMLPluginTemp)后, 创建项目会自动生成两个.cpp两个.h和一个qmldir文件
修改qmldir文件如下,module项名称就是后面导入的模块名称,和变量命名一样,不要有.或者其他特殊符号;plugin项就是新建插件的项目名称

qmldir 文件

module MyPlugin

plugin QMLPluginTemp
1
2
3
4
5
#ifndef MYITEM_H
#define MYITEM_H

#include <QQuickItem>

class MyItem : public QQuickItem
{
Q_OBJECT
Q_DISABLE_COPY(MyItem)

public:
MyItem(QQuickItem *parent = 0);
~MyItem();

Q_INVOKABLE void read();

};

#endif // MYITEM_H

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "myitem.h"
#include <QDebug>
MyItem::MyItem(QQuickItem *parent):
QQuickItem(parent)
{
// By default, QQuickItem does not draw anything. If you subclass
// QQuickItem to create a visual item, you will need to uncomment the
// following line and re-implement updatePaintNode()

// setFlag(ItemHasContents, true);
}

MyItem::~MyItem()
{
}


void MyItem::read()
{

qWarning() << "qml cpp plugin ";
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#pragma once

#include <QQmlExtensionPlugin>

class QMLPluginTempPlugin: public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")

public:
void registerTypes(const char *uri);
};

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "qmlplugintemp_plugin.h"
#include "myitem.h"

#include <qqml.h>

void QMLPluginTempPlugin::registerTypes(const char *uri)
{
// @uri com.mycompany.qmlcomponents
qmlRegisterType<MyItem>(uri, 1, 0, "MyItem");
}

1
2
3
4
5
6
7
8
9
10
11
构建项目后,在生成目录下找到qmldir文件和QMLPluginTemp.dll或QMLPluginTempd.dll(根据生成类型,debug还是release),放到一个新建文件夹MyPlugin(qmldir文件中的模块名)中,再将MyPlugin文件夹放入新建文件夹DLL中。
main函数中指定DLL文件夹路径

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);

QQmlApplicationEngine engine;
engine.addImportPath("D:/QML/DLL/");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

return app.exec();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
随后就可以在QML文件中使用插件
如果不指定,在Qt安装路径如D:\ProgramFiles\Qt\Qt580\5.8\mingw53_32\qml目录新建文件夹MyPlugin,把QMLPluginTemp.dll,QMLPluginTempd.dll和qmldir复制到MyPlugin文件夹内。

import QtQuick 2.6
import QtQuick.Window 2.2
import MyPlugin 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")

MainForm {
anchors.fill: parent
mouseArea.onClicked: {
cppPlugin.read()
console.log(qsTr('Clicked on background. Text: "' + textEdit.text + '"'))
}

}

MyItem{
id:cppPlugin
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
3.暴露法
使用 setContextProperty,是将对象或数据暴露给 QML,一般默认就是全局单例。 函数原型

void QQmlContext::setContextProperty(const QString &name, QObject *value)
void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
1
2
int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QQmlApplicationEngine engine;
engine.rootContext( )->setContextProperty(
"Greeting",
QObject::tr( "Hello QML from C++" ) );//变量,qml中直接就可用此属性的值

engine.rootContext( )->setContextProperty(
"CPlusPlusClass",
new CPlusPlusClass() );//对象,此处new的时候创建对象了
//setContextProperty,在qml中是全局的
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));

return app.exec();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Window {
title: qsTr("Hello World")
width: 640
height: 480
visible: true
Text {
id: text
text: Greeting //直接就可以使用此属性
anchors.centerIn: parent
}
Button {

anchors.top: text.bottom
text: "CPlusPlusClass.method()"
MouseArea {

anchors.fill: parent
onClicked: {
CPlusPlusClass.method()//调用类中的方法
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
引用链接
QML与C++交互
————————————————
版权声明:本文为CSDN博主「52_赫兹的鲸」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40194498/article/details/109592155

 

标签:调用,const,int,void,C++,CppObject,QML,include
From: https://www.cnblogs.com/im18620660608/p/17091483.html

相关文章

  • Qml调用C++方法初探
    为什么会在QML中调用C++方法?引入Qml的一个重要目的就是UI和逻辑的解耦,我们可以把业务逻辑用C++实现,Qml只用来开发界面,这样在后续程序改版过程中,基本上可以不动逻辑只改UI比......
  • QML(14)——QML与C++交互方式总结1/3(qml调用C++的public函数)
    一、效果qml文件中,可以调用C++类的公共函数   二、步骤1、C++类文件创建C++文件时,一定要勾选下面3项 MyQmlClass.h #ifndefMYQMLCLASS_H#defineMYQMLCL......
  • C++校园导游系统[2023-02-04]
    C++校园导游系统[2023-02-04]校园导游问题描述:用无向网表示校园景点平面图,图中顶点表示主要景点,存放景点的编号、名称、简介等信息,图中的边表示景点间的道路,存放路径......
  • C++ 引用:他是坤坤也是鸡哥
    一、前言作为一名ikun,我最喜欢的明星就是坤坤,但是坤坤又不只叫坤坤,因为他的成名之作《鸡你太美》,ikun们就经常亲切的叫他鸡哥。这个过程中,鸡哥就是我们ikun给偶像坤坤......
  • 【Frida】Java反射调用
    通过反射调用,获取类名参数Objectobj类名Stringstr方法名staticObjecta(Objectobj,Stringstr){try{returnobj.getClass().getMet......
  • 【Java AWT 图形界面编程】Frame 窗口标题栏大小问题 ( Container 容器的空白边框 Ins
    文章目录​​一、Frame窗口标题栏大小问题​​​​二、Container容器的空白边框Insets​​​​三、获取Frame窗口的标题栏高度代码​​​​四、修改后的代码示例​​......
  • c++ 一键提取pdf文件图片工具
    日常工作的时候,有时候需要将一个pdf文件中的图片全部提取出来使用,那么这时候就需要一个简单的方法来做这个事情,而不是一个一个图片截图做操作。效果如下:工具下载地址:​​pdf......
  • C/C++BUG: [Error] invalid array assignment
    在写字符串赋值给结构体成员的时候出现的报错报错的行,代码表示改变数据BookName,是将数据存储到结构体中,但是这样赋值会报错。报错这是结构体的组成,result是指向链表其......
  • PyQT调用ui界面文件
    通过QtDesigner将ui文件转存为py文件不继承Ui_FormimportsysfromPySide6importQtCore,QtWidgetsfromPySide6.QtWidgetsimport*fromui_testimportUi_Form......
  • c++函数
    一,函数基础1.函数一般用一个名字表示,即函数名。返回类型,函数名,参数列表,和函数体构成了函数定义。函数定义的语法形式类型说明符 函数名(含类型说明的形式参数表){ 函数体}......