使用多个视图在QML中查看,编辑和更新数据(来自C ++),而数据保留在C ++中(订阅数据) [英] View, edit and update data (from C++ ) in QML with multiple views, while the Data stays in C++ (subscribe to data)

查看:516
本文介绍了使用多个视图在QML中查看,编辑和更新数据(来自C ++),而数据保留在C ++中(订阅数据)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在C ++类(Data.cpp)的实例中存储了一些数据.现在,我希望能够从QML中的2个单独的表示形式中查看和编辑此数据,以便如果View1中的值发生更改,则数据本身(C ++)也会发生更改,View2也显示该值(因为它已得到通知)当C ++数据更改时.)

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(提供数据列表)

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部分:

    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
        }
    }

现在,如果我单击view1中的一个项目(例如),我想更改相应数据的名称,并相应地在view2中显示该名称.如果我使用C ++修改了名称,则新名称应同时显示在两个视图中.

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.

我问了有关此主题的更具体问题,请点击此处.

推荐答案

这很有可能,但是您遇到了一些问题:

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

  1. 您想将数据对象列表公开为QQmlListProperty.这是将列表放入QML的正确方法
  2. 如果您的列表正确显示为QQmlListProperty,则可以将其设置为ListView的模型,而无需执行您现在正在执行的怪异的getModel()黑客操作
  3. 您不应在getter中将项目添加到列表中,否则,每次QML尝试阅读时,都将其添加到列表中.

解决后,您只需与委托中对当前模型项的引用进行交互,即可更新Data对象.

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

这是一个完整的工作示例.我在QML中添加了一个可以更改模型的MouseArea,还可以在C ++中添加一个可以更改模型的计时器,以显示对任一侧所做的更改都会立即反映在UI中.

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
    }
}

这篇关于使用多个视图在QML中查看,编辑和更新数据(来自C ++),而数据保留在C ++中(订阅数据)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆