上一篇大概大致针对Qml调用C++ 方法进行了一个入门,方式可以大致分成注册和暴露两种方法。每种方式的优劣性必须根据开发的实际情况进行探究,但注册法是我认为更适用界面和逻辑分离的一种方法。
QMl之Q_PROPERTYQ_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 #includeclass 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 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("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的元对象系统的识别的关键!



