XML не изменяется в ListView

Я пытаюсь создать пример для динамического изменения XML-модели данных в моем файле .qml (когда я нажимаю кнопку) с использованием C ++. Для этого я возвращаю свойство Qt (GroupDataModel). Но после возврата объекта ListView не меняется, хотя я вижу, что свойство модели возвращается снова.

OBS: если я загружаю его из XMLDataModel в .qml, вместо загрузки в код 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>

1

Решение

Функции Q_INVOKABLE являются своего рода слотами, поэтому они не могут возвращать объект.
Вы должны найти ListView и поместить модель данных.

  • Добавьте в QML после id: objectName: «listview»
  • Получите listView в C ++: ListView * listView = root-> findChild («listView»);
  • установить DataModel: listView-> setDataModel (m_model);
1

Другие решения

Вам нужен только ваш setGroupDataModel() быть Q_INVOKABLE — остальные просто принадлежат имуществу.

Но вы неправильно понимаете GroupDataModel. Вы не хотите излучать onModelChanged() если модель НЕДВИЖИМОСТИ не изменится. В вашем случае СОБСТВЕННОСТЬ не изменилась, все, что изменилось, это значения в недвижимость. Так что вам не нужно 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 учебный класс. Я до сих пор не совсем понял — и боюсь, у меня больше нет времени сейчас — но я попытался в своем конструкторе:

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. Как я уже сказал, я еще не разобрался, как заставить это работать. Домашнее задание? (пожалуйста, напишите, когда вы решите это)

Всего наилучшего,
С

1

Если вы действительно хотите отобразить «пользовательские» данные в качестве заголовка, то вы можете использовать точный код, предложенный @craigmj в своем ответе, чтобы получить ваши данные в модель, но просто измените определение ListItemComponent в вашем main.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
}
}
]
}
0