前言
上一篇大概大致针对Qml调用C++ 方法进行了一个入门,方式可以大致分成注册和暴露两种方法。每种方式的优劣性必须根据开发的实际情况进行探究,但注册法是我认为更适用界面和逻辑分离的一种方法。
QMl之Q_PROPERTY
Q_PROPERTY这个自定属性,大家肯定不陌生。简单说一下,这里就不作深入讲解。
Q_PROPERTY(type name # 属性
READ getFunction # 读取属性值,返回属性的类型的值or指针or引用
[WRITE setFunction] # 设置属性值,至少具有一个参数
[RESET resetFunction] # 设置属性的值到默认值
[NOTIFY notifySignal] # 属性的值发生改变时发出信号
[CONSTANT] # 属性的值是不变的
[FINAL] # 属性不能被派生类所重写,有些情况下,这可以用于效率优化,但不是被moc强制的
[DESIGNABLE bool] # 此属性是否在界面设计器的属性编辑器中出现(忽略)
[SCRIPTABLE bool] # 属性是否可以被一个脚本引擎操作(忽略)
[STORED bool] # 属性是否被认为是独立存在还是依赖于其它的值而存在(忽略)
[USER bool]) # 属性是否被设计为面向用户的或用户可修改的类属性(忽略)
- C++ 类
//==========================QTestData.h==============================//
#pragma once
#include <QObject>
class QTestData : public QObject {
Q_OBJECT
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY NameChanged)
public:
QTestData(QObject *parent=nullptr);
~QTestData();
QString getName();
void setName(QString name);
signals:
void NameChanged(QString name);
private:
QString name_;
};
//==========================QTestData.cpp==============================//
#include "QTestData.h"
#include <QDebug>
QTestData::QTestData(QObject *parent) : QObject(parent) {
connect(this, &QTestData::NameChanged, this, [this](QString name) {
qDebug() << "sigNameChanged new_name=" << name;
});
}
QTestData::~QTestData() {}
QString QTestData::getName() {
qDebug() << __FUNCTION__;
return name_;
}
void QTestData::setName(QString name) {
qDebug() << __FUNCTION__;
if (name_ == name) {
return;
}
name_ = name;
emit NameChanged(name);
}
- 调用方法暴露法(setContextProperty)or注册法(qmlRegisterType)
//==========================注册调用==============================//
{
qmlRegisterType<QTestData>("test.conrtrol", 1, 1, "CppTestData");
QQuickWidget *qml_widget = new QQuickWidget();
qml_widget->setResizeMode(QQuickWidget::SizeRootObjectToView);
qml_widget->setSource(QUrl("signal_qml.qml"));
qml_widget->show();
ui.verticalLayout->addWidget(qml_widget);
}
//==========================暴漏调用==============================//
//略
- Qml实现释义(以注册法为例)
- 定义一个Cpp注册的类型CppTestData
- 如果有Cpp有信号,则把对应的信号,加上"on"前缀,则自动实现了Qml中对应的槽函数(如:NameChanged ->onNameChanged)
- 在槽函数中进行更新UI
import QtQuick 2.12
import QtQuick.Window 2.14
import QtQuick.Controls 2.14
import QtQuick.Controls.Styles 1.4
import test.conrtrol 1.1
Rectangle {
color: "gray"
radius:10
CppTestData {
id: cpp_data
onNameChanged: {
console.log("onNameChanged ", name)
background_image.source=name
}
}
Image {
id:background_image
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
source: "http://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg"
antialiasing: true
}
Button {
text: "Left"
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin:50
background: Rectangle {
color:"#0b81ff"
implicitWidth: 100;
implicitHeight: 50;
radius: 6;
}
//信号槽连接
onClicked: {
cpp_data.NameChanged("http://image.nbd.com.cn/uploads/articles/images/673466/500352700_banner.jpg")
console.log("我被点击了"+text)
}
}
Button {
text: "Right"
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.rightMargin:50
background: Rectangle {
color:"#0b81ff"
implicitWidth: 100;
implicitHeight: 50;
radius: 6;
}
//信号槽连接
onClicked: {
cpp_data.name="http://image.nbd.com.cn/uploads/articles/images/673466/500352700_banner.jpg"
console.log("我被点击了"+text)
}
}
}
深入思考
在Qml中什么样的C++类型接口才能被调用?
- Q_INVOKABLE 宏修饰
- Q_PROPERTY修饰的元对象系统访问的属性
- 信号( signals)或槽函数(public slots)
总结:元对象系统可识别的方法
在Qml能识别的C++类关键点?
- QObject 的派生类
- 必须有Q_OBJECT 宏
两个条件是C++ 类被Qt的元对象系统的识别的关键!