View, edit and update data (from C++ ) in QML with multiple views, while the Data stays in C++ (subscribe to data)

和自甴很熟 提交于 2019-12-08 00:12:20

问题


I have some data stored in instances of a C++ class (Data.cpp). Now i want to be able to view and edit this data from 2 seperate representations in QML, so that if the values in View1 are changed, the data itself (C++) is changed and the value displayed by View2 as well (because it gets notified when the C++ data changes).

Here is what I got so far:

Data.h

class Data : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

public:
    Data(std::string name);
    QString name();
    void setName(const QString &n);

signals:
    void nameChanged();

private:
    std::string _name;
};

Parser.h (provides a list of Data)

class Parser : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<QObject*> list READ list NOTIFY listChanged)
    //QList<Data*> is not working with QML :(

public:
    Parser(QObject *parent = 0);
    QList<QObject*> list() //stuff below is implementd in Parser.cpp
    {
       _list.append(new Data("name 1"));
       _list.append(new Data("name 2"));
       _list.append(new Data("name 3"));
        return _list;
    }


signals:
    void listChanged();

private:
    QList<QObject*> _list;
};

QML part:

    ListView
    {
        id: view1
        anchors.fill: parent
        spacing: 5
        delegate: Text { text: name}
        model: ListModel{Component.onCompleted: getModel()}
    }
    ListView
    {
        id: list2
        anchors.fill: parent
        spacing: 5
        delegate: Text { text: name}
        model: ListModel{Component.onCompleted: getModel()}
    }
    function getModel()
    {
        var m = parser.list;
        for(var i=0; i<m.length; i++)
        {
            list.model.append(m[i]); //simply returning the list (m) does not work
        }
    }

Now if I click on an item in view1 (for example) i want the name of the corresponding Data to change, and the name displayed in view2 accordingly. If I modified the name from C++, the new name should be displayed in both views.

Is there any way to do this? I'm stuck on this for days... Thanks for your help.


EDIT:

I asked a more specific question to this topic here.


回答1:


It's very much possible, but you've got a few problems:

  1. You want to expose your list of Data objects as a QQmlListProperty. This is the proper way to get lists into QML
  2. If your list is properly exposed as a QQmlListProperty you can just set it as the model of your ListView without doing that weird getModel() hack that you're doing now
  3. You shouldn't be added items to your list in the getter or else you'll be appending to it every time QML tries to read it.

Once that's resolved, you can update a Data object simply by interacting with the reference to the current model item in your delegate.

Here's a full working example. I've added a MouseArea in the QML that changes the model and also a timer in C++ that also changes the model, to show that changes to either side are instantly reflected in the UI.

main.cpp:

#include <QGuiApplication>
#include <QtQuick>

class Data : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

public:
    Data(const QString &n) : _name(n) { }
    QString name() const { return _name; }

    void setName(const QString &n) {
        if (_name == n)
            return;
        _name = n;
        emit nameChanged(n);
    }

signals:
    void nameChanged(const QString &n);

private:
    QString _name;
};

class Parser : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QQmlListProperty<Data> list READ list CONSTANT)

public:
    Parser(QObject *parent = 0) {
        _list.append(new Data(QStringLiteral("name 1")));
        _list.append(new Data(QStringLiteral("name 2")));
        _list.append(new Data(QStringLiteral("name 3")));

        startTimer(5000);
    }

    QQmlListProperty<Data> list() {
        return QQmlListProperty<Data>(this, _list);
    }

    void timerEvent(QTimerEvent *) {
        _list[1]->setName(_list[1]->name() + QStringLiteral("C++"));
    }

private:
    QList<Data*> _list;
};

int main(int argc, char *argv[])
{
    QGuiApplication a(argc, argv);

    qmlRegisterType<Data>();

    QQuickView view;
    view.rootContext()->setContextProperty(QStringLiteral("parser"), new Parser);
    view.setSource(QUrl("qrc:///qml/main.qml"));
    view.showNormal();

    return a.exec();
}

#include "main.moc"

main.qml:

import QtQuick 2.0

Rectangle {
    width: 800
    height: 600

    ListView {
        id: view1
        anchors { top: parent.top; left: parent.left; bottom: parent.bottom }
        width: parent.width / 2
        spacing: 5

        delegate: Item {
            height: 30
            width: parent.width

            Text { text: name }

            MouseArea {
                anchors.fill: parent
                onClicked: model.name += "1";
            }
        }
        model: parser.list
    }

    ListView {
        id: view2
        anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
        width: parent.width / 2
        spacing: 5

        delegate: Item {
            height: 30
            width: parent.width

            Text { text: name }

            MouseArea {
                anchors.fill: parent
                onClicked: model.name += "2";
            }
        }
        model: parser.list
    }
}


来源:https://stackoverflow.com/questions/19841328/view-edit-and-update-data-from-c-in-qml-with-multiple-views-while-the-dat

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!