由于QML引擎与Qt元对象系统的紧密集成,可以从QML代码访问由QObject派生的类适当公开的任何功能。这使得C ++类的属性和方法可以直接从QML访问,通常很少或无需修改。
QML引擎能够通过元对象系统内省QObject实例。这意味着,任何QML代码都可以访问QObject派生类实例的以下成员:
- 属性(使用Q_PROPERTY注册的属性)
- 方法(需注册为public slots或是标记为Q_INVOKABLE)
- 信号
(此外,如果已使用Q_ENUMS声明枚举,则可以使用枚举。)
通常,无论是否已向QML类型系统注册了QObject派生类,都可以从QML访问它们。但是,如果QML引擎要访问其他类型信息(例如,如果要将类本身用作方法参数或属性,或者要将其中一个枚举类型用于以这种方式使用),那么该类可能需要注册。
cppobject.h
#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
cppobject.cpp
#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;
}
man.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "cppobject.h"
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
qmlRegisterType<CppObject>("MyCppObject",1,0,"CppObject");
QQmlApplicationEngine engine;
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);
return app.exec();
}
main.qml
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="优快云" //修改属性会触发set函数,获取值会触发get函数
cpp_obj.year=2020
cpp_obj.sendSignal() //调用Q_INVOKABLE宏标记的函数
}else{
console.log('----qml 点击右键:QML发射信号')
root.qmlSignalA()
root.qmlSignalB('优快云',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)
}
}
这个例子很好的诠释C++与QML 的互相交互的过程。