Qt QML数据模型似乎不适用于C++

问题描述:

我一直在使用QML声明性数据模型上的Qt页面http://doc.qt.digia.com/4.7/qdeclarativemodels.html中的示例。特别是,我正在使用Qt SDK附带的objectlistmodel示例(在examples/declarative/modelviews/objectlistmodel中)。这一切似乎工作得很好,直到我试图将它与QMLPageControl示例在http://www.developer.nokia.com/Community/Wiki/How_to_create_a_Page_Control_component_in_QMLQt QML数据模型似乎不适用于C++

当我尝试用QML的ListView这样显示基于QML的ListModel(填入QML ListElements):

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 } 

     } 
    } 
} 

...一切工作相当不错。这完全按预期工作 - 一个窗口弹出一些带有彩色背景的文本。

ListView displaying a QML ListModel

然后,我可以做一些更复杂,就像使用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 
      } 
     } 
    } 
} 

同样,这一切按预期工作 - 一个窗口,一个flickable,dragable列表弹出的彩色框。

PathView displaying a QML ListModel

PathView displaying a QML ListModel, in motion

备份,那么我可以在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 

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(); 
    } 
} 

然后,我将它添加到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。

ListView displaying a QList in C++

我想获得工作是一个C++模型来头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 
//  //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对话框中居中。

C++ QList in a QML PathView

和Debug控制台上我看到这一点:

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有足够接近QML的ListModel/ListItem集合为一个ListView显示基本形状,但不足以让PathView显示。

有没有人有任何想法可能会出错?不幸的是,QML类文档并没有真正地与编写一致的C++替代品的目标放在一起。例如,http://qt-project.org/doc/qt-4.8/qml-pathview.html的PathView对象文档没有说明它的模型需要支持哪些属性。而且,ListModel文档不是确定性的 - 它没有明确说明ListModel支持哪些属性,也没有关于QList如何满足这些要求以及如何不准确的文档。

更新:我已经在Windows上用Qt 5试过了,而且我仍然遇到同样的问题。

事实证明,有一个很简单的原因,cppModelcount属性不可用 - 这是因为无论QAbstractListModel也不QList<>count财产!

我曾以为,这样一个事实:ListModel可以用C++来取代 - 基于对象像的QList <>意味着他们多态性和一个ListView或PathView会使用count属性来正确地处理它们。

首先,QAbstractListModelQList<>都不是多态性。事实证明,它们都是特殊的 - ListView知道它是否具有ListModelQList<>QAbstractListModel,并且具有独立的代码路径以使用每个代码路径。 ListView不需要不存在的count属性来管理QList<>QAbstractListModel。其实,我不清楚ListViewPathView哪怕使用ListModelcount属性。 count属性似乎主要是为了QML程序员的好处。在我的示例中,我使用count属性在PathView中构建了一个Path对象。我的例子完美,如果我使用length属性代替原因,因为QList<>length属性。

感谢blam和torgeirl在#qt-qml帮助我完成这个任务(既不想通过发布这个答案来收集*点,所以我发布它为社区的利益)。

+0

QList有一个count属性:http://qt-project.org/doc/qt-5/qlist.html#count-2 – johnbakers