Qt QML 数据模型似乎不适用于 C++ [英] Qt QML data model doesn't seem to work with C++

查看:49
本文介绍了Qt QML 数据模型似乎不适用于 C++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在使用 http://doc.qt 中的示例.digia.com/4.7/qdeclarativemodels.html 这是关于 QML 声明性数据模型的 Qt 页面.特别是,我正在使用 Qt SDK 附带的 objectlistmodel 示例(在 examples/declarative/modelviews/objectlistmodel 中).在我尝试将它与 http 上的 QMLPageControl 示例结合起来之前,这一切似乎都运行良好://www.developer.nokia.com/Community/Wiki/How_to_create_a_Page_Control_component_in_QML.

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.

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

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

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.

然后,我可以做一些更复杂的事情,比如使用 PathView:

Then, I can do something a bit more complicated, like use a 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.

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

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

数据对象.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.
";

}

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.
";

}


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

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

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

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

然后我将它添加到 QML 上下文中:

And then I add it to the QML context:

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

And finally, in the QML, I add this C++ model to the 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.

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.

我希望得到一个支持 PathView 的 C++ 模型,如下所示:

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

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 对话框中居中.

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.

在调试控制台上我看到了这个:

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

看起来 QList 的基本形状与 QML ListModel/ListItem 集合足够接近以供 ListView 显示,但不够接近以供 PathView 显示.

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.

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

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.

更新:我已经在 Windows 上使用 Qt 5 进行了尝试,但我仍然遇到同样的问题.

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

推荐答案

原来cppModelcount属性不存在的原因很简单可用 - 这是因为 QAbstractListModelQList<> 都没有 count 属性!

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!

我曾假设 ListModel 可以替换为基于 C++ 的对象(如 QList<>),这意味着它们是多态的,并且 ListView 或 PathView 将使用 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.

首先,QAbstractListModelQList<> 都不具有 ListModel 的多态性.事实证明,它们都只是特殊情况 - ListView 知道它是否具有 ListModelQList<>QAbstractListModel 并有单独的代码路径供使用.ListView 不需要不存在的 count 属性来管理 QList<>QAbstractListModel.事实上,我不清楚 ListViewPathView 甚至使用 ListModelcount 属性.count 属性似乎主要是为了 QML 程序员的利益.在我的示例中,我使用 count 属性在 PathView 中构建了一个 Path 对象.如果我使用 length 属性代替,我的示例将完美运行,因为 QList<> 确实具有 length 属性.

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.

感谢 #qt-qml 上的 blam 和 torgeirl 帮助我解决这个问题(他们都不想通过发布这个答案来收集 stackoverflow 积分,所以我发布它是为了社区的利益).

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

这篇关于Qt QML 数据模型似乎不适用于 C++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆