1

我正在尝试制作一个示例,以使用 C++ 在我的 .qml 文件(当我单击按钮时)中动态更改 XML 数据模型。为此,我返回了一个 Qt 属性(GroupDataModel)。但是在返回对象后, ListView 并没有改变,虽然我看到模型属性再次返回。

OBS:如果我从 .qml 中的 XMLDataModel 加载它,而不是加载 C++ 代码,它就可以工作。

这是我的 XmlTest.hpp:

#ifndef XmlTest_HPP_
#define XmlTest_HPP_

#include <QObject>
#include <bb/cascades/GroupDataModel>

namespace bb { namespace cascades { class Application; }}

class XmlTest : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bb::cascades::GroupDataModel* model READ model NOTIFY onModelChanged);
public:
    XmlTest(bb::cascades::Application *app);
    virtual ~XmlTest() {}

    Q_INVOKABLE
    bb::cascades::GroupDataModel *model();

    Q_INVOKABLE
    void setGroupDataModel();
signals:
    void onModelChanged();
private:
    bb::cascades::GroupDataModel *m_model;
};

#endif /* XmlTest_HPP_ */

和 XmlTest.cpp:

#include "XmlTest.hpp"

#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>
#include <bb/data/XmlDataAccess>

using namespace bb::cascades;
using namespace bb::data;

XmlTest::XmlTest(Application *app)
: QObject(app)
{
    m_model = new GroupDataModel();
    qRegisterMetaType<GroupDataModel *>("GroupDataModel *");

    QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);
    qml->setContextProperty("_xmlTest", this);

    AbstractPane *root = qml->createRootObject<AbstractPane>();
    app->setScene(root);
}

GroupDataModel *XmlTest::model()
{
    qDebug("Returning m_model");
    return m_model;
}

void XmlTest::setGroupDataModel()
{
    XmlDataAccess xml;
    QVariant xmlData = xml.load(QDir::currentPath() + "/app/native/assets/models/model.xml");
    m_model->clear();
    m_model->insertList(xmlData.toList());
    qDebug("File loaded");
    emit this->onModelChanged();
}

我的 main.qml 文件(只是一个带有按钮的 ListView):

import bb.cascades 1.0

Page {
    Container {
        id: mainContainer
        layout: DockLayout {}
        ListView {
            id: listView
            dataModel: _xmlTest.model
            //dataModel: XmlDataModel {
            //    source: "models/model2.xml"
            //}
            onDataModelChanged: {
                console.log("Data model changed!"); 
            }
            listItemComponents: [
                ListItemComponent {
                    type: "user"
                    StandardListItem {
                        title: ListItemData.realname
                        description: ListItemData.name
                    }
                },
                ListItemComponent {
                    type: "option"
                    StandardListItem {
                        title: ListItemData.title
                    }
                }
            ]
        }
        Button {
            text: "Click"
            onClicked: {
                console.log("Trying to load file");
                _xmlTest.setGroupDataModel();
            }
            verticalAlignment: VerticalAlignment.Bottom
            horizontalAlignment: HorizontalAlignment.Center
        }
    }
}

和我试图加载的 XML:

<root>
    <user name="myUsername" realname="My Real Name"/>
    <option title="Option 1"/>
    <option title="Option 2"/>
    <option title="Option 3"/>
    <option title="Option 4"/>
    <option title="Option 5"/>
</root>
4

3 回答 3

1

你只需要你setGroupDataModel()Q_INVOKABLE- 其他人只是财产访问者。

但是您误解了 GroupDataModel。onModelChanged()除非模型 PROPERTY 更改,否则您不想发出 a 。在您的情况下, PROPERTY 没有改变,所有改变的是属性的值。所以你不需要emit onModelChanged(), 我认为它应该有新的值作为参数。

那么问题出在哪里?

您需要检查是否正确地从 XML 文件中读取数据。

然后您需要阅读GroupDataModel - 如果我正确阅读它,它只会使用“item”和“header”作为项目类型,因此不会使用您的 ListItemComponents。

如果不使用 GroupDataModel 而是使用 XmlDataModel ,它会更容易一些(并且会起作用;-)

这是我的XmlListView.hpp主要课程(您的XmlTest课程):

// Default empty project template
#ifndef XmlListView_HPP_
#define XmlListView_HPP_

#include <QObject>
#include <bb/cascades/XmlDataModel>
#include <bb/cascades/DataModel>

namespace bb { namespace cascades { class Application; }}

class XmlListView : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bb::cascades::DataModel *model READ model NOTIFY onModelChanged);
public:
    XmlListView(bb::cascades::Application *app);
    virtual ~XmlListView() {}

    bb::cascades::DataModel *model();
    Q_INVOKABLE void setGroupDataModel();

signals:
    void onModelChanged();
private:
    bb::cascades::XmlDataModel *m_model;
};


#endif /* XmlListView_HPP_ */

和.cpp:

// Default empty project template
#include "XmlListView.hpp"

#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>

#include <bb/data/XmlDataAccess>

using namespace bb::cascades;
using namespace bb::data;

XmlListView::XmlListView(bb::cascades::Application *app)
: QObject(app)
{
    m_model = new XmlDataModel();

    QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);
    qml->setContextProperty("_xmlTest", this);

    AbstractPane *root = qml->createRootObject<AbstractPane>();
    app->setScene(root);
}

DataModel *
XmlListView::model() {
    return m_model;
}

void
XmlListView::setGroupDataModel() {
    m_model->setSource(QUrl("models/model.xml"));
}

我的 main.qml,和你的一样:

import bb.cascades 1.0

Page {
    Container {
        id: mainContainer
        layout: DockLayout {}
        ListView {
            id: listView
            dataModel: _xmlTest.model
            listItemComponents: [
                ListItemComponent {
                    type: "user"
                    StandardListItem {
                        title: ListItemData.realname
                        description: ListItemData.name
                    }
                },
                ListItemComponent {
                    type: "option"
                    StandardListItem {
                        title: ListItemData.title
                    }
                }
            ]

        }
        Button {
            text: "Click"
            onClicked: {
                _xmlTest.setGroupDataModel()
            }
            verticalAlignment: VerticalAlignment.Bottom
            horizontalAlignment: HorizontalAlignment.Center
        }

    }
}

.xml 模型文件和你的一样。

要真正了解哪里出错了,您需要检查XmlDataAccess类中的 ehte 数据加载。我还没有完全解决它-恐怕我现在没有更多时间了-但是我在构造函数中尝试了:

qDebug() << "==========================================================";
XmlDataAccess xml;
QVariant xmlData = xml.load(QDir::currentPath() + "/app/native/assets/models/model.xml");
if (xml.hasError()) {
    qDebug(xml.error().errorMessage().toAscii());
} else {
    QVariantList list = xmlData.toList();
    qDebug() << "list len = " << list.size();
}
qDebug() << "==========================================================";

观看我的调试日志,我看到list len = 0, 所以这段代码没有成功地从 XML 中读取任何内容。正如我所说,我还没有弄清楚如何让它工作。家庭作业?(请在完成后发布)

一切顺利,C

于 2013-01-16T09:15:36.200 回答
1

Q_INVOKABLE 函数是某种插槽,因此它们不能返回对象。您应该找到 ListView 并放置数据模型。

  • 在 id: objectName: "listview" 之后添加 QML
  • 在 C++ 中获取 listView: ListView* listView = root->findChild("listView");
  • 设置数据模型:listView->setDataModel(m_model);
于 2013-01-15T17:37:18.570 回答
0

如果您真正想要的是将“用户”数据显示为标题,那么您可以使用@craigmj 在他的回答中建议的确切代码将您的数据放入模型中,但只需更改ListItemComponentmain 中的定义。 qml 来Header代替StandardListItem. 我提供了ListView下面的全部内容,您应该可以将其放入您的 main.qml 中。Header记录在这里

    ListView {
        id: listView
        dataModel: _xmlTest.model

        onDataModelChanged: {
            console.log("Data model changed!");
        }
        listItemComponents: [
            ListItemComponent {
                type: "user"
                Header {
                    title: ListItemData.realname
                    subtitle: ListItemData.name
                }
            },
            ListItemComponent {
                type: "option"
                StandardListItem {
                    title: ListItemData.title
                }
            }
        ]
    }
于 2013-01-24T05:58:29.993 回答