Я пытаюсь создать пример для динамического изменения 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>
Функции Q_INVOKABLE являются своего рода слотами, поэтому они не могут возвращать объект.
Вы должны найти ListView и поместить модель данных.
Вам нужен только ваш 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. Как я уже сказал, я еще не разобрался, как заставить это работать. Домашнее задание? (пожалуйста, напишите, когда вы решите это)
Всего наилучшего,
С
Если вы действительно хотите отобразить «пользовательские» данные в качестве заголовка, то вы можете использовать точный код, предложенный @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
}
}
]
}