2013-01-14 1 views
1

C++을 사용하여 XML 데이터 모델을 (. 단추를 클릭하면) .qml 파일에서 dinamically 변경하도록 예제를 만들려고합니다. 이를 위해 Qt 속성 (GroupDataModel)을 반환합니다. 그러나 개체를 반환 한 후에도 ListView는 변경되지 않지만 model 속성이 다시 반환되는 것을 볼 수 있습니다.XML이 ListView에서 변경되지 않습니다.

OBS : C++ 코드로로드하는 대신 .qml의 XMLDataModel에서로드하면 작동합니다. XmlTest.cpp

#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_ */ 

과 :

#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) :

내 XmlTest.hpp입니다

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를 찾고 데이터 모델을 넣어야합니다. 개체 이름 :

  • ID 다음에 QML에 추가

    "목록보기"
  • 는 C++로 목록보기를 가져옵니다 : ListView에 * 목록보기 = 루트 레벨> findChild ("목록보기");
  • DataModel을 설정합니다. listView-> setDataModel (m_model);
+1

Q_INVOKABLE은 슬롯이 아니며 QML에 노출 된 메서드 일뿐입니다. 그들은 값을 반환 할 수 있습니다. – craigmj

1

setGroupDataModel()Q_INVOKABLE이어야합니다. 다른 것은 단지 속성 접근 자일뿐입니다.

그러나 GroupDataModel을 오해하고 있습니다. 모델 PROPERTY가 변경되지 않으면 onModelChanged()을 내 보내지 않습니다. 귀하의 경우 PROPERTY는 변경되지 않았으며, 변경된 모든 것은 값입니다. 따라서 emit onModelChanged()이 필요하지 않습니다. 매개 변수로 새 값을 가져야합니다.

그래서 문제가 어디에 있습니까?

XML 파일의 데이터를 올바르게 읽는지 확인해야합니다.

GroupDataModel에서 읽어야합니다. 올바르게 읽는 경우 항목 유형으로 '항목'과 '헤더'만 사용되므로 ListItemComponents는 사용되지 않습니다.

XmlDataModel을 사용하는 GroupDataModel을 사용하는 대신 조금 쉽습니다 (;-) 작동합니다.

// 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")); 
} 

내 주요

은 여기 내 XmlListView.hpp 메인 클래스 (당신의 XmlTest 클래스)입니다.귀하의 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

+0

맞습니다. 문제는 .toList()를 호출 할 때 데이터가 파싱되는 방식에 있습니다. 어떻게 든 QML에서 XMLDataModel을 사용할 때 작동하는 파일은 C++ 코드에서 파싱 할 때 작동하지 않습니다. 하지만 머리글과 항목을 사용하는 방법을 아직 찾지 못했습니다. –

+0

XMLDataModel을 사용하는 경우 "사용자"와 "옵션"을 구분할 수 있습니다. 너 무슨 뜻이야 ...? '사용자'노드를 [n]의 indexPath로, 옵션을 [n, o]의 indexPath로 사용 하시겠습니까? – craigmj

+0

정말 중요하지 않습니다. 내가 원했던 것은 '사용자'를 헤더로, '옵션'을 표준 항목으로 차별화하는 것이 었습니다. GroupDataModel을 사용하고 있는데, XmlDataModel을 시도했을 때 화면에 나타나지 않았지만 QVariantList를 사용하면 노드의 이름을 알 수 없습니다. –

0

헤더로 '사용자의 데이터를 표시하는 것입니다 무엇을 당신이 정말로 원하는, 당신은 제안 정확한 코드를 사용할 수있는 경우 @ (당신이 그것을 해결할 때 게시하시기 바랍니다) 그의 답변에서 craigmj를 사용하여 데이터를 모델로 가져 왔지만 main.qml에있는 ListItemComponent의 정의를 StandardListItem 대신 Header으로 변경하십시오. 아래에 전체 ListView을 제공 했으므로 main.qml에 그냥 놓을 수 있어야합니다. Headerhere이라고 기록되어 있습니다.

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