Model danych Qt QML nie działa z C ++

Pracowałem z przykładami whttp://doc.qt.digia.com/4.7/qdeclarativemodels.html która jest stroną Qt w deklaratywnych modelach danych QML. W szczególności pracuję zobjectlistmodel przykład dostarczany z zestawem Qt SDK (w przykładach / deklaratywnych / modelviews / objectlistmodel). Wszystko wydaje się działać całkiem dobrze, dopóki nie spróbuję połączyć go z przykładem QMLPageControl pod adresemhttp://www.developer.nokia.com/Community/Wiki/How_to_create_a_Page_Control_component_in_QML.

Kiedy próbuję wyświetlić oparty na QML ListModel (wypełniony QML ListElements) z ListView QML w ten sposób:

import QtQuick 1.0

Rectangle {
   width: 200; height: 200

   ListModel {
       id: qmlModel
       ListElement { name: "qml entry1 (red)"; colour: "red" }
       ListElement { name: "qml entry2 (orange)"; colour: "orange" }
       ListElement { name: "qml entry3 (yellow)"; colour: "yellow" }
       ListElement { name: "qml entry4 (green)"; colour: "green" }
       ListElement { name: "qml entry5 (blue)"; colour: "blue" }
       ListElement { name: "qml entry6 (purple)"; colour: "purple" }
   }


   ListView {

       id: list_view

       anchors.fill: parent
       model: qmlModel
       delegate: Rectangle {
           height: 20
           width: 200
           color: colour
           Text { text: name }

       }
    }
}

... wszystko działa całkiem dobrze. Działa to całkowicie zgodnie z oczekiwaniami - pojawia się okno z tekstem na kolorowych tłach w pasmach.

Następnie mogę zrobić coś nieco bardziej skomplikowanego, np. Użyć PathView:

import QtQuick 1.0

Rectangle {
    width: 200; height: 200

    ListModel {
        id: qmlModel
        ListElement { name: "qml entry1 (red)"; colour: "red" }
        ListElement { name: "qml entry2 (orange)"; colour: "orange" }
        ListElement { name: "qml entry3 (yellow)"; colour: "yellow" }
        ListElement { name: "qml entry4 (green)"; colour: "green" }
        ListElement { name: "qml entry5 (blue)"; colour: "blue" }
        ListElement { name: "qml entry6 (purple)"; colour: "purple" }
    }


    //       ListView {
    //           id: list_view
    //           anchors.fill: parent
    //           model: qmlModel
    //           delegate: Rectangle {
    //               height: 20
    //               width: 200
    //               color: colour
    //               Text { text: name }
    //           }
    //       }

    PathView {
        id: my_path_view

        anchors.fill: parent

        Keys.onRightPressed: if (!moving && interactive) incrementCurrentIndex()
        Keys.onLeftPressed: if (!moving && interactive) decrementCurrentIndex()

        flickDeceleration: 500

        preferredHighlightBegin: 0.5
        preferredHighlightEnd: 0.5
        focus: true
        interactive: true
        model: qmlModel

        delegate: Rectangle {
            width: 100
            height: 100
            color: colour
            Text {
                anchors.centerIn: parent
                text: name
            }
        }


        path: Path {
            startX: - my_path_view.width * my_path_view.model.count / 2 + my_path_view.width / 2
            startY: my_path_view.height / 2
            PathLine {
                x: my_path_view.width * my_path_view.model.count / 2 + my_path_view.width / 2
                y: my_path_view.height / 2
            }
        }
    }
}

Ponownie, wszystko to działa zgodnie z oczekiwaniami - pojawia się okno z klikalną, przeciągalną listą kolorowych pól.

Wykonując kopię zapasową, mogę zdefiniować obiekt danych w C ++ w następujący sposób:

dataobject.h

#ifndef DATAOBJECT_H
#define DATAOBJECT_H

#include <QObject>

class DataObject : public QObject
{
    Q_OBJECT

    Q_PROPERTY( QString name READ name WRITE setName NOTIFY nameChanged )
    Q_PROPERTY( QString colour READ colour WRITE setColour NOTIFY colourChanged )


public:
    DataObject( QObject * parent = 0 );
    DataObject( const QString &_name, const QString &_color, QObject * parent=0 );

    QString name() const;
    void setName(const QString &);

    QString colour() const;
    void setColour(const QString &);

signals:
    void nameChanged();
    void colourChanged();


private:
    QString m_name;
    QString m_colour;
};


#endif // DATAOBJECT_H

dataobject.cpp

#include "dataobject.h"
#include <QDebug>

DataObject::DataObject( QObject * parent )
    : QObject( parent )
{
    qDebug() << "DataObject::DataObject() has been called.\n";

}

DataObject::DataObject( const QString &_name, const QString &_colour, QObject * parent )
    : QObject( parent )
    , m_name( _name )
    , m_colour( _colour )
{
    qDebug() << "DataObject::DataObject(name, color) has been called.\n";

}


QString DataObject::name() const {
    qDebug() << "name() has been called.\n";
    return m_name;
}

void DataObject::setName(const QString &name) {
    qDebug() << "setName has been called.\n";
    if ( name != m_name ) {
        m_name = name;
        emit nameChanged();
    }
}

QString DataObject::colour() const {
    qDebug() << "colour() has been called.\n";
    return m_colour;
}

void DataObject::setColour(const QString &colour) {
    qDebug() << "setColour has been called.\n";
    if ( colour != m_colour ) {
        m_colour = colour;
        emit colourChanged();
    }
}

A potem dodaję go do kontekstu QML:

#include <QApplication>
#include <QDialog>
#include <QDeclarativeView>
#include <QDeclarativeContext>
#include <QLayout>
#include <QDir>
#include "qmlapplicationviewer.h"
#include "dataobject.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QList<QObject*> dataList;
    dataList.append( new DataObject( "c++ entry1 (red)", "red" ) );
    dataList.append( new DataObject( "c++ entry2 (orange)", "orange" ) );
    dataList.append( new DataObject( "c++ entry3 (yellow)", "yellow" ) );
    dataList.append( new DataObject( "c++ entry4 (green)", "green" ) );
    dataList.append( new DataObject( "c++ entry5 (blue)", "blue" ) );
    dataList.append( new DataObject( "c++ entry6 (purple)", "purple" ) );

    QmlApplicationViewer viewer;
    viewer.rootContext()->setContextProperty( "cppModel", QVariant::fromValue(dataList) );
    viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
#if defined( Q_OS_MAC )
    viewer.setMainQmlFile("../Resources/qml/main.qml");
#elif defined( Q_OS_WIN32 )
    viewer.setMainQmlFile("qml/main.qml");
#else
#error - unknown platform
#endif
    viewer.showExpanded();

    return app.exec();
}

I wreszcie, w QML, dodaję ten model C ++ do ListView:

import QtQuick 1.0

Rectangle {
    width: 200; height: 200

    ListModel {
        id: qmlModel
        ListElement { name: "qml entry1 (red)"; colour: "red" }
        ListElement { name: "qml entry2 (orange)"; colour: "orange" }
        ListElement { name: "qml entry3 (yellow)"; colour: "yellow" }
        ListElement { name: "qml entry4 (green)"; colour: "green" }
        ListElement { name: "qml entry5 (blue)"; colour: "blue" }
        ListElement { name: "qml entry6 (purple)"; colour: "purple" }
    }


           ListView {

               id: list_view

               anchors.fill: parent
               //model: qmlModel
               model: cppModel
               delegate: Rectangle {
                   height: 20
                   width: 200
                   color: colour
                   Text { text: name }

               }
           }

}

Po raz kolejny działa to dobrze - pojawia się dialog z tekstem na kolorowym tle ułożonym w pasy. Wyświetlanie ListView wspieranego przez model C ++ wydaje się działać z każdym bitem, a także wyświetlać ListView wsparte przez QML ListModel.

Chciałbym pracować w modelu C ++ wspierającym PathView w następujący sposób:

import QtQuick 1.0

Rectangle {
    width: 200; height: 200

    ListModel {
        id: qmlModel
        ListElement { name: "qml entry1 (red)"; colour: "red" }
        ListElement { name: "qml entry2 (orange)"; colour: "orange" }
        ListElement { name: "qml entry3 (yellow)"; colour: "yellow" }
        ListElement { name: "qml entry4 (green)"; colour: "green" }
        ListElement { name: "qml entry5 (blue)"; colour: "blue" }
        ListElement { name: "qml entry6 (purple)"; colour: "purple" }
    }


//    ListView {

//       id: list_view

//       anchors.fill: parent
//       model: qmlModel
//       //model: cppModel
//       delegate: Rectangle {
//           height: 20
//           width: 200
//           color: colour
//           Text { text: name }

//       }
//    }

    PathView {
        id: my_path_view

        anchors.fill: parent

        Keys.onRightPressed: if (!moving && interactive) incrementCurrentIndex()
        Keys.onLeftPressed: if (!moving && interactive) decrementCurrentIndex()

        flickDeceleration: 500

        preferredHighlightBegin: 0.5
        preferredHighlightEnd: 0.5
        focus: true
        interactive: true
        //model: qmlModel
        model: cppModel

        delegate: Rectangle {
            width: 100
            height: 100
            color: colour
            Text {
                anchors.centerIn: parent
                text: name
            }
        }


        path: Path {
            startX: - my_path_view.width * my_path_view.model.count / 2 + my_path_view.width / 2
            startY: my_path_view.height / 2
            PathLine {
                x: my_path_view.width * my_path_view.model.count / 2 + my_path_view.width / 2
                y: my_path_view.height / 2
            }
        }
    }
}

To NIE działa. Widzę kolorowe prostokąty, ale nie można z nimi korzystać za pomocą myszy i nie są one wyśrodkowane w oknie dialogowym qmlviewer.

I na konsoli debugowania widzę to:

QDeclarativeDebugServer: Waiting for connection on port 3768...
QDeclarativeDebugServer: Connection established
QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call
QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call
colour() has been called.

name() has been called.

colour() has been called.

name() has been called.

colour() has been called.

name() has been called.

colour() has been called.

name() has been called.

colour() has been called.

name() has been called.

colour() has been called.

name() has been called.

QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call
QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call
QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call
QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call
QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call

Wygląda na to, że QList ma podstawowy kształt, który jest wystarczająco blisko kolekcji QML ListModel / ListItem, aby wyświetlić ListView, ale nie na tyle blisko, aby wyświetlić PathView.

Czy ktoś ma pojęcie, co może się nie udać? Niestety dokumentacja klasy QML nie jest tak naprawdę połączona z celem pisania zgodnych standartów C ++. Na przykład dokumentacja obiektu PathView pod adresemhttp://qt-project.org/doc/qt-4.8/qml-pathview.html nie mówi, jakie właściwości powinien obsługiwać jego model. Co więcej, dokumentacja ListModel nie jest definitywna - nie określa dokładnie, jakie właściwości obsługuje ListModel i nie ma jasnej dokumentacji dotyczącej tego, jak dokładnie QList spełnia te wymagania i jak nie.

AKTUALIZACJA: Próbowałem tego z Qt 5 w systemie Windows i nadal mam ten sam problem.

questionAnswers(1)

yourAnswerToTheQuestion