首页 文章

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

提问于
浏览
2

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

当我尝试使用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
            }
        }
    }
}

同样,这一切都按预期工作 - 一个窗口弹出一个可滑动,可拖动的彩色框列表 .

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

我想要工作的是支持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对话框中居中 .

C++ QList in a QML PathView

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

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对象文档没有确定性 - 它没有明确的文档说明QList如何精确满足这些要求以及它是如何满足这些要求的 .

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

1 回答

  • 8

    事实证明,有一个非常简单的原因, cppModelcount 属性不是't available - it',因为 QAbstractListModelQList<> 都没有 count 属性!

    我假设 ListModel 可以替换为像CList <>这样的基于C的对象这一事实意味着它们是多态的,并且ListView或PathView将使用 count 属性来正确处理它们 .

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

    感谢#qt-qml上的blam和torgeirl帮助我(不想通过发布这个答案收集stackoverflow点,所以我发布它是为了社区的利益) .

相关问题