首页 > 解决方案 > 正确的 QML <-> C++ 声明式方法

问题描述

我在 C++ 层更新了一些数据结构。我必须在 qml 中显示它并将更改从 qml 层保存到 c++ 结构。我希望有一种声明性的方法来做到这一点,但我迫切地想要找到它。这是代码的一部分:

C++ 头文件:

#ifndef NODEINFO_H
#define NODEINFO_H

#include <QObject>
#include <QString>

class NodeInfo : public QObject {
    Q_OBJECT
    Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged)
public:
    NodeInfo(QObject *parent = 0);
    virtual ~NodeInfo() {}

    const QString& label() const;
    void setLabel(const QString& val);
signals:
    void labelChanged();
private:
    QString d_label;
};

#endif // NODEINFO_H

C++ 正文:

#include "nodeinfo.h"
#include <QDebug>

NodeInfo::NodeInfo(QObject *parent) : QObject(parent), d_label("Test string") {
}

const QString &NodeInfo::label() const {
    qDebug() << "NodeInfo::label: getter";
    return d_label;
}

void NodeInfo::setLabel(const QString &val) {
    qDebug() << "NodeInfo::label: setter - " << val;
    d_label = val;
    emit labelChanged();
}

主文件

#include <QGuiApplication>
#include <QDebug>
#include <QQmlContext>
#include <QQuickView>
#include <QQmlApplicationEngine>
#include "nodeinfo.h"

int main(int argc, char *argv[]) {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

//    qmlRegisterType<NodeInfo>("NodeInfo", 1, 0, "NodeInfo");

    NodeInfo  nodeDescr;

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("nodeData", &nodeDescr);

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    engine.load(url);
    QObject *root = engine.rootObjects().value(0);
    if (QWindow *window = qobject_cast<QWindow *>(root))
        window->show();
    else
        return -1;
    return app.exec();
}

qml代码:

import QtQuick 2.15
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12

ApplicationWindow {
    id: root
    width: 360
    height: 520
    visible: true

//    property alias a_label: nodeData.label
    Column {
        anchors.fill: parent
        TextInput {
            id: simpleTxt
            text: nodeData.label
        }
        Text {
            id: txt
            text: nodeData.label
        }
        Button {
            text: "writeProp"
            onClicked: nodeData.label = simpleTxt.text
        }
//        Binding {
//            target: nodeData
//            property: "label"
//            value: simpleTxt.text
//        }
    }
}

因此,当我在 TextInput 中编辑文本时,它应该自动在 c++ 代码中设置属性,但事实并非如此。只有当我按下按钮。正如您在评论中看到的那样,有一种绑定方式,它可以工作,但我希望这不是一种真正的方式。让我们想象一下,如果我的 c++ 结构中有 15-30 个或更多数据字段,并且如果我必须以这种方式进行 30 次绑定,或者我需要在每个数据字段上编写信号/插槽并连接它们,那么这完全是垃圾。但什么是正确的方法?任何想法表示赞赏

标签: c++qtqml

解决方案


text: nodeData.label设置绑定 nodeData.label --> 文本(一个方向)。即,只要 nodeData.label 更改,文本就会更新。当用户在字段中键入一些文本时,此绑定将被销毁。

因此,如果您想在用户更改文本时更新 nodeData.label,则需要使用 onTextChaged 事件。

Text {
    onTextChanged: nodeData.label = text
}

changed还有一点需要注意:在发出适当的信号之前,您需要检查属性是否真的发生了变化。所以代码应该是这样的:

void NodeInfo::setLabel(const QString &val) {
    qDebug() << "NodeInfo::label: setter - " << val;
    if (d_label != val)
    {
         d_label = val;
         emit labelChanged();
     }
}

这将防止您的代码无休止的绑定循环。


推荐阅读