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

时间:2021-03-31 03:18:33

I've been working with the examples in http://doc.qt.digia.com/4.7/qdeclarativemodels.html which is the Qt page on QML declarative data models. In particular, I'm working with the objectlistmodel example that comes with the Qt SDK (in examples/declarative/modelviews/objectlistmodel). It all seems to work reasonably well, until I try to combine it with the QMLPageControl example at http://www.developer.nokia.com/Community/Wiki/How_to_create_a_Page_Control_component_in_QML.

我一直在使用http://doc.qt.digia.com/4.7/qdeclarativemodels.html中的示例,它是QML声明性数据模型的Qt页面。特别是,我正在使用Qt SDK附带的objectlistmodel示例(在示例/声明式/模型视图/objectlistmodel中)。这一切似乎都运行得相当好,直到我尝试将它与http://www.developer.nokia.com/community/wiki/how_create_a_page_control_component_in_qml的qml示例结合起来。

When I try to display a QML-based ListModel (populated with QML ListElements) with a QML ListView like this:

当我尝试显示一个基于QML的ListModel(包含QML listelement)时,使用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 }

       }
    }
}

...everything works quite nicely. This works entirely as expected - a window pops up with some text across colored backgrounds in bands.

…一切都很好地工作。这完全是意料之中的事情——一个窗口弹出,在不同颜色的背景中以条带显示一些文本。

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

Then, I can do something a bit more complicated, like use a PathView:

然后,我可以做一些更复杂的事情,比如使用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
            }
        }
    }
}

Again, this all works as expected - a window pops up with a flickable, dragable list of colored boxes.

同样,这一切按预期工作——一个窗口弹出一个可滚动的彩色盒子列表。

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

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

Backing up, I can then define a data object in C++ like this:

然后,我可以像这样在c++中定义一个数据对象:

dataobject.h

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

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

And then I add it to the QML context:

然后我将它添加到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();
}

And finally, in the QML, I add this C++ model to the ListView:

最后,在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 }

               }
           }

}

Once again, this works just fine - a dialog with text against colored backgrounds arranged in bands appears. Displaying a ListView backed by a C++ model seems to work every bit as well as displaying a ListView backed by a QML ListModel.

同样地,这也很好——一个文本与颜色背景排列成带的对话框出现了。显示一个由c++模型支持的ListView和显示一个由QML ListModel支持的ListView似乎是一样的。

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

What I'd like to get working is a C++ model backing a PathView like this:

我想让一个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
            }
        }
    }
}

This DOESN'T work. What I see is the colored rectangles, but they can't be interacted with with the mouse and they aren't centered in the qmlviewer dialog.

这并不工作。我看到的是有颜色的矩形,但是它们不能与鼠标交互,而且它们不在qmlviewer对话框的中心。

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

And on the debug console I see this:

在调试控制台,我看到:

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

It seems like a QList has a basic shape that's close enough to a QML ListModel/ListItem collection for a ListView to display, but not close enough for a PathView to display.

似乎QList的基本形状与ListModel/ListItem集合非常接近,可以显示ListView,但与PathView不够接近。

Does anyone have any idea what might be going wrong? Unfortunately the QML class documentation isn't really put together with the goal of writing conformant C++ stand-ins. For example, the PathView object documentation at http://qt-project.org/doc/qt-4.8/qml-pathview.html doesn't say what properties its model needs to support. Moreover, the ListModel documentation isn't definitive - it doesn't state exactly what properties the ListModel supports and there's no clear documentation on how precisely a QList satisfies those requirements and how it doesn't.

有没有人知道哪里出了问题?不幸的是,QML类文档并没有真正与编写符合c++标准的标准结合在一起。例如,http://qt-project.org/doc/qt-4.8/qml-pathview.html的PathView对象文档没有说明模型需要支持哪些属性。此外,ListModel文档并不确定——它没有确切地说明ListModel支持哪些属性,也没有明确的文档说明QList如何精确地满足这些需求,以及它如何不满足这些需求。

UPDATE: I've tried this with Qt 5 on Windows, and I'm still having the same problem.

更新:我在Windows上尝试过qt5,但我还是遇到了同样的问题。

1 个解决方案

#1


7  

It turns out that there's a very simple reason that the count property of the cppModel isn't available - it's because neither QAbstractListModel nor QList<> have a count property!

cppModel的count属性是不可用的,原因很简单——因为QAbstractListModel和QList<>都没有count属性!

I had assumed that the fact that a ListModel could be substituted with a C++-based object like a QList<> meant that they were polymorphic and that a ListView or PathView would use a count property to correctly handle them.

我假设ListModel可以替换为基于c++的对象(如QList<>),这意味着它们是多态的,而ListView或PathView会使用一个count属性来正确处理它们。

First, neither QAbstractListModel nor QList<> are polymorphic with a ListModel. It turns out that they're all just special-cased - a ListView knows whether it has a ListModel or a QList<> or a QAbstractListModel and has separate code paths for using each. The ListView doesn't need the nonexistent count property to manage a QList<> or a QAbstractListModel. In fact, it isn't clear to me that ListView and PathView even use ListModel's count property. The count property seems to be mostly for the QML programmer's benefit. In my example, I was using the count property to build a Path object in the PathView. My example works perfectly if I use a length property instead because QList<> DOES have a length property.

首先,QAbstractListModel和QList<>对于ListModel都不是多态性的。结果是,它们都是特殊的- ListView知道它是否有ListModel或QList<>或QAbstractListModel,并且有单独的代码路径来使用它们。ListView不需要不存在的count属性来管理QList<>或QAbstractListModel。事实上,我并不清楚ListView和PathView是否使用了ListModel的count属性。count属性似乎主要是为了QML程序员的利益。在我的示例中,我使用count属性在PathView中构建路径对象。如果我使用一个length属性,那么我的示例就能很好地工作,因为QList<>确实有一个length属性。

Thanks to blam and torgeirl on #qt-qml for helping me with this (neither wanted to collect the * points by posting this answer, so I'm posting it for the benefit of the community).

感谢blam和torgeirl在#qt-qml上的帮助(他们都不希望通过发布这个答案来收集*点,所以我发布它是为了社区的利益)。

#1


7  

It turns out that there's a very simple reason that the count property of the cppModel isn't available - it's because neither QAbstractListModel nor QList<> have a count property!

cppModel的count属性是不可用的,原因很简单——因为QAbstractListModel和QList<>都没有count属性!

I had assumed that the fact that a ListModel could be substituted with a C++-based object like a QList<> meant that they were polymorphic and that a ListView or PathView would use a count property to correctly handle them.

我假设ListModel可以替换为基于c++的对象(如QList<>),这意味着它们是多态的,而ListView或PathView会使用一个count属性来正确处理它们。

First, neither QAbstractListModel nor QList<> are polymorphic with a ListModel. It turns out that they're all just special-cased - a ListView knows whether it has a ListModel or a QList<> or a QAbstractListModel and has separate code paths for using each. The ListView doesn't need the nonexistent count property to manage a QList<> or a QAbstractListModel. In fact, it isn't clear to me that ListView and PathView even use ListModel's count property. The count property seems to be mostly for the QML programmer's benefit. In my example, I was using the count property to build a Path object in the PathView. My example works perfectly if I use a length property instead because QList<> DOES have a length property.

首先,QAbstractListModel和QList<>对于ListModel都不是多态性的。结果是,它们都是特殊的- ListView知道它是否有ListModel或QList<>或QAbstractListModel,并且有单独的代码路径来使用它们。ListView不需要不存在的count属性来管理QList<>或QAbstractListModel。事实上,我并不清楚ListView和PathView是否使用了ListModel的count属性。count属性似乎主要是为了QML程序员的利益。在我的示例中,我使用count属性在PathView中构建路径对象。如果我使用一个length属性,那么我的示例就能很好地工作,因为QList<>确实有一个length属性。

Thanks to blam and torgeirl on #qt-qml for helping me with this (neither wanted to collect the * points by posting this answer, so I'm posting it for the benefit of the community).

感谢blam和torgeirl在#qt-qml上的帮助(他们都不希望通过发布这个答案来收集*点,所以我发布它是为了社区的利益)。