为什么会在QML中调用C++方法?
- 引入Qml的一个重要目的就是UI和逻辑的解耦,我们可以把业务逻辑用C++实现,Qml只用来开发界面,这样在后续程序改版过程中,基本上可以不动逻辑只改UI
- 比如有一些复杂的计算逻辑,我们可以通过C++来实现,这样效率来说也会更高
QML调用C++方法主要有两种方式
本文主要详解Q_INVOKABLE的关键字,通过两种方法来调用C++ 方法
1.创建一个C++方法类
利用Qt的元对象,通过Q_INVOKABLE或public slots注册到元对象系统中,进而通过函数名称直接进行调用。这里先创建一个QObject的派生类,用于实现Qml中需要调用的方法
#pragma once
#include <QObject>
class QmlControl : public QObject
{
Q_OBJECT
public:
QmlControl(QObject *parent=nullptr);
~QmlControl();
Q_INVOKABLE void AddData(int a,int b);
Q_INVOKABLE QString UpdateBackground();
};
#include "QmlControl.h"
#include <QDebug>
QmlControl::QmlControl(QObject *parent) : QObject(parent) {}
QmlControl::~QmlControl() {}
void QmlControl::AddData(int a, int b) {
qDebug() << "a=" << a << "b=" << b;
qDebug() << "a+b=" << a + b;
}
QString QmlControl::UpdateBackground() {
return QString("http://image.nbd.com.cn/uploads/articles/images/673466/500352700_banner.jpg");
}
2.1 qmlRegisterType注册法
使用qmlRegisterType注册一个可以被Qml识别的类型并调用
qmlRegisterType<QmlControl>("test.conrtrol", 1, 0, "QmlControl");
QQuickWidget *qml_widget = new QQuickWidget();
qml_widget->setResizeMode(QQuickWidget::SizeRootObjectToView);
qml_widget->setSource(QUrl("test_qml.qml"));
qml_widget->show();
ui.verticalLayout->addWidget(qml_widget);
关系图
import QtQuick 2.12
import QtQuick.Window 2.14
import QtQuick.Controls 2.14
import QtQuick.Controls.Styles 1.4
import test.conrtrol 1.0
Rectangle {
color: "gray"
radius:10
QmlControl {
id: qmlctrl
}
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: {
qmlctrl.AddData(99,88);
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: {
background_image.source=qmlctrl.UpdateBackground();
console.log("我被点击了"+text)
}
}
}
2.2 setContextProperty暴露法
通过 setContextProperty暴露给Qml,这里都是以QQuickWidget举例(Qml与QWidget混合开发)
QQuickWidget *qml_widget = new QQuickWidget();
qml_widget->rootContext()->setContextProperty("qml_ctrl", &qml_control);
qml_widget->setResizeMode(QQuickWidget::SizeRootObjectToView);
qml_widget->setSource(QUrl("test_qml.qml"));
qml_widget->show();
ui.verticalLayout->addWidget(qml_widget);
这种暴露的方式,无需要引入包名,并且在外部定义了C++类,调用C++方法为
> 注册名.function()
//qml_ctrl.UpdateBackground();
//qml_ctrl.AddData(99,88);
关系图
暴露法和注册法区别
- setContextProperty 的暴露法C++类实列化一次,可能同时被多个qml共享,C++类需要我们来维护生命周期,要自己手动释放。在QQuickWidget控件中,如果不同的QQuickWidget共享了同一个QQmlApplicationEngine,则这个QQmlApplicationEngine下暴露的C++类是共享的。
- qmlRegisterType 则是每个文件qml中创建由C++导出的类型,实例后使用,全局不唯一。
|