4

QML 宣言型データ モデルに関する Qt ページであるhttp://doc.qt.digia.com/4.7/qdeclarativemodels.htmlの例を使用してきました。特に、objectlistmodelQt SDK (examples/declarative/modelviews/objectlistmodel 内) に付属の例を使用しています。http://www.developer.nokia.com/Community/Wiki/How_to_create_a_Page_Control_component_in_QMLで QMLPageControl の例と組み合わせようとするまで、すべてがうまく機能しているようです。

QML ベースの ListModel (QML ListElements が入力された) を QML 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
       delegate: Rectangle {
           height: 20
           width: 200
           color: colour
           Text { text: name }

       }
    }
}

...すべてが非常にうまく機能します。これは完全に期待どおりに機能します。バンド内の色付きの背景にテキストが表示されたウィンドウがポップアップします。

QML ListModel を表示する ListView

次に、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
            }
        }
    }
}

繰り返しますが、これはすべて期待どおりに機能します。ウィンドウがポップアップし、色付きのボックスのフリックおよびドラッグ可能なリストが表示されます。

QML ListModel を表示する PathView

動作中の QML ListModel を表示する PathView

バックアップすると、次のように C++ でデータ オブジェクトを定義できます。

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

データオブジェクト.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();
    }
}

そして、それを 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();
}

最後に、QML で、この C++ モデルを 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 }

               }
           }

}

繰り返しますが、これは問題なく機能します。帯状に配置された色付きの背景に対するテキストを含むダイアログが表示されます。C++ モデルに裏打ちされた ListView の表示は、QML ListModel に裏打ちされた ListView を表示するだけでなく、すべての部分で機能しているようです。

C++ で QList を表示する ListView

私がやりたいのは、次のような PathView をサポートする C++ モデルです。

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

これは機能しません。色付きの長方形が表示されますが、マウスで操作できず、qmlviewer ダイアログの中央に配置されていません。

QML PathView の C++ QList

そして、デバッグ コンソールに次のように表示されます。

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

QList には、ListView を表示するには QML ListModel/ListItem コレクションに十分近いが、PathView を表示するには十分に近い基本的な形状があるようです。

何がうまくいかないのか誰にも分かりませんか?残念ながら、QML クラスのドキュメントは、適合する C++ スタンドインを作成するという目標に合わせてまとめられたものではありません。たとえば、http://qt-project.org/doc/qt-4.8/qml-pathview.html にある PathView オブジェクトのドキュメントには、そのモデルがサポートする必要のあるプロパティが記載されていません。さらに、ListModel のドキュメントは決定的なものではありません。ListModel がサポートするプロパティが正確に記載されておらず、QList がそれらの要件をどの程度正確に満たし、どのように満たしていないかについての明確なドキュメントもありません。

更新: Windows 上の Qt 5 でこれを試しましたが、まだ同じ問題が発生しています。

4

1 に答える 1

9

countプロパティがcppModel利用できないのには、非常に単純な理由があることがQAbstractListModelわかりました。QList<>count

ListModelQList<> のような C++ ベースのオブジェクトで a を置き換えることができるという事実は、それらが多態的であり、ListView または PathView がcountプロパティを使用してそれらを正しく処理することを意味すると想定していました。

まず、 もQAbstractListModelQList<>ポリモーフィックではありませんListModel。それらはすべて特殊なケースであるListViewことがわかります- a は、 aListModelまたは aQList<>または aのいずれQAbstractListModelを持っているかを認識し、それぞれを使用するための個別のコード パスを持っています。は、またはを管理するためListViewに存在しないcountプロパティを必要としません。実際、それは私には明らかではなく、のプロパティを使用することさえできません。このプロパティは、主に QML プログラマーの利益のためのもののようです。私の例では、プロパティを使用して にオブジェクトを作成していました。DOES にはプロパティがあるため、代わりにプロパティを使用すると、私の例は完全に機能します。QList<>QAbstractListModelListViewPathViewListModelcountcountcountPathPathViewlengthQList<>length

これを手伝ってくれた#qt-qmlのblamとtorgeirlに感謝します(どちらもこの回答を投稿してstackoverflowポイントを収集したくなかったので、コミュニティの利益のために投稿しています)。

于 2013-04-11T06:03:40.170 に答える