在Qml和C++类进行数据交互时,通用的办法都是注册C++到Qml中,但是很多时候C++的对象是在C++中进行创建,如果在Qml中创建了,数据之间的交互就会出现无法控制的问题。
信号与槽、上下文等都是数据交互的方式,但是当嵌套多层时,内部的C++对象和内部的Qml内容交互无法直接连接。此时就需要通过一个代理的C++类作为数据和消息的连接通道。
利用一个中间的代理类实现嵌套的消息和数据的交互,注册为engine的上下文
例子:
class HiddenClass {
public:
int getData() const { return 42; }
};
// 中间代理类
class ProxyClass : public QObject {
Q_OBJECT
Q_PROPERTY(int data READ data NOTIFY dataChanged)
public:
explicit ProxyClass(QObject *parent = nullptr) :QObject(parent), m_hiddenClass()
{}
int data() const { return m_hiddenClass.getData(); }
signals:
void dataChanged();
private:
HiddenClass m_hiddenClass;
};
// main.qml
import QtQuick
import QtQuick.Window
Window {
width: 640
height: 480
visible: true
title: "Indirect C++ Access"
Text {
id: textItem
anchors.centerIn: parent
text: "Data from hidden class: " + proxy.data
}
}
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
ProxyClass proxy;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("proxy", &proxy);
const QUrl url(u"qrc:/main.qml"_qs);
engine.load(url);
return app.exec();
}
嵌套的交互,通知类、触发类的动作可以通过嵌套的信号与槽和C++绑定
#include <QObject>
class MyClass : public QObject {
Q_OBJECT
public:
explicit MyClass(QObject *parent = nullptr) : QObject(parent) {}
signals:
void dataChanged(const QString &newData);
public slots:
void updateData(const QString &data) {
emit dataChanged(data);
}
};
// main.qml
import QtQuick
import QtQuick.Window
Window {
width: 640
height: 480
visible: true
title: "Nested QML Interaction"
// 嵌套的QML组件
MyNestedComponent {
id: nestedComponent
}
Component.onCompleted: {
myObject.dataChanged.connect(nestedComponent.onDataChanged);
}
Button {
id: updateButton
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
text: "Update Data"
onClicked: {
myObject.updateData("New data from QML");
}
}
}
// MyNestedComponent.qml
import QtQuick
Item {
width: 200
height: 100
Text {
id: textItem
anchors.centerIn: parent
text: "Initial data"
}
signal dataChangedFromC++(string newData)
function onDataChanged(newData) {
textItem.text = newData;
}
}
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "myclass.h"
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
MyClass myObject;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("myObject", &myObject);
const QUrl url(u"qrc:/main.qml"_qs);
engine.load(url);
return app.exec();
}
使用 findChild
方法查找嵌套对象,通过将QQmlEngine对象全局化,实现通过engint的root找到嵌套的对象,
// main.qml
import QtQuick
import QtQuick.Window
Window {
width: 640
height: 480
visible: true
title: "Find Nested QML Object"
Item {
id: nestedItem
objectName: "nestedItem"
function doSomething() {
console.log("Doing something in nested item");
}
}
}
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QObject>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(u"qrc:/main.qml"_qs);
engine.load(url);
QObject *root = engine.rootObjects().first();
if (root) {
// 查找嵌套的QML对象
QObject *nestedObject = root->findChild<QObject*>("nestedItem");
if (nestedObject) {
// 调用嵌套对象的方法
QMetaObject::invokeMethod(nestedObject, "doSomething");
}
}
return app.exec();
}