1

C++ を使用して、(ボタンをクリックしたときに) .qml ファイルで XML データモデルを動的に変更する例を作成しようとしています。そのために、Qt プロパティ (GroupDataModel) を返しています。しかし、オブジェクトを返した後、ListView は変更されませんが、モデル プロパティが再び返されることがわかります。

OBS: C++ コードでロードする代わりに、.qml の XMLDataModel からロードすると、機能します。

これは私の 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クラスからのデータの読み込みを調べる必要があります。私はまだそれを完全に解決していません-そして、今はもう時間がないのではないかと思います-しかし、コンストラクターで試しました:

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");
  • DataModel を設定します: listView->setDataModel(m_model);
于 2013-01-15T17:37:18.570 に答える
0

「ユーザー」データをヘッダーとして表示することが本当に必要な場合は、@craigmj の回答で提案された正確なコードを使用してデータをモデルに取り込むことができますがListItemComponent、メインの定義を変更するだけです。Headerの代わりに使用する qml 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 に答える