一、目的
qml文件中,可以调用C++对象的成员属性(变量),及对应的信号函数
二、步骤
1、C++类文件
创建C++文件时,一定要勾选下面3项
MyQmlClass.h
#ifndef MYQMLCLASS_H
#define MYQMLCLASS_H
#include <QObject>
class MyQmlClass : public QObject {
Q_OBJECT
// 暴露成员属性
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
Q_PROPERTY(int year READ getYear WRITE setYear NOTIFY yearChanged)
public:
explicit MyQmlClass(QObject *parent = nullptr);
// 属性对应的接口函数
void setName(const QString &name);
QString getName() const;
void setYear(int year);
int getYear() const;
signals:
// 属性对应的信号函数
void nameChanged(const QString name);
void yearChanged(int year);
private:
// 成员变量 / 属性
QString m_Name;
int m_Year;
};
#endif // MYQMLCLASS_H
选项说明
其实我们在实际使用中,很少能够用全 Q_PROPERTY 的所有选项,这里介绍些常用的选项:
-
type 是属性的类型,可以是 int、QString、QObject、QColor 等等,name 就是属性的名字。
-
READ 标记,如果你没有为属性指定 MEMBER 标记,则 READ 标记必不可少。声明一个读取属性的函数,该函数一般没有参数,返回定义的属性。
-
WRITE 标记,可选配置。声明一个设定属性的函数。它指定的函数,只能有一个与属性类型匹配的参数,必须返回 void 。
-
NOTIFY 标记,可选配置。给属性关联一个信号(该信号必须是已经在类中声明过的),当属性的值发生变化时就会触发该信号。信号的参数,一般就是你定义的属性。
MyQmlClass.cpp
#include "myqmlclass.h"
#include <QDebug>
MyQmlClass::MyQmlClass(QObject *parent)
: QObject(parent), m_Name("xingxing"), m_Year(20) {}
void MyQmlClass::setName(const QString &name) {
qDebug() << "MyQmlClass::setName";
if (m_Name != name) {
qDebug() << "emit namechanged";
m_Name = name;
// 触发信号是emit控制,信号和槽 是connect控制
emit nameChanged(name);
}
}
QString MyQmlClass::getName() const {
qDebug() << "MyQmlClass::getName";
return m_Name;
}
void MyQmlClass::setYear(int year) {
qDebug() << "MyQmlClass::setYear";
if (m_Year != year) {
qDebug() << "emit yearchanged";
m_Year = year;
emit yearChanged(m_Year);
}
}
int MyQmlClass::getYear() const {
qDebug() << "MyQmlClass::getYear";
return m_Year;
}
2、注册
注册有两种方式
方式1: engine.rootContext()->setContextProperty("myQml", &myQmlImp);
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "myqmlclass.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);
QQmlApplicationEngine engine;
//【 方式1:创建一个C++对象,注册给qml使用 】
MyQmlClass myQmlImp;
engine.rootContext()->setContextProperty("myQml", &myQmlImp);
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();
}
方式2:qmlRegisterType<MyQmlClass>("MyClass.module", 1, 0, "MyQml");
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "myqmlclass.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);
QQmlApplicationEngine engine;
//【方式2: 把整个C++类注册到qml,作为qml的一个组件对象】
qmlRegisterType<MyQmlClass>("MyClass.module", 1, 0, "MyQml");
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();
}
3、qml中使用
3.1
如果注册时使用方式1,qml中可以直接使用 注册名.function()myQml.getValue()
使用这种方式时,IDE不会自动提示相关关键字,但是完成后运行实现了效果。
具体使用场景可看 上一篇博文:
https://blog.youkuaiyun.com/wangpailiulanqi8/article/details/124625817
3.2
如果注册时使用方式2,使用C++类就像QML 的组件一样,需要导库,创建,调用
Register03.qml
import QtQuick 2.0
import QtQuick.Controls 2.15
import MyClass.module 1.0
Item {
id: root
//cpp类作为一个qml对象
MyQml {
id: cpp_obj
property int counts: 0
//qml对象的每个属性都有对应的onPropertyChanged
onYearChanged: {
console.log("onYearChanged ", year)
counts++
}
onCountsChanged: {
console.log("onCountsChanged ", counts)
name = "NAMECHANGE"
}
onNameChanged: {
console.log("onNameChanged ", name)
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.LeftButton) {
console.log("--- 点击左键:cpp发出信号")
// 修改属性 触发cpp信号函数 namechanged
cpp_obj.name = "wangyue"
cpp_obj.year = 1996
}
}
}
}
main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Loader {
id: contentPane
anchors.fill: parent
}
Component.onCompleted: contentPane.source = "qrc:/Register03.qml"
}