Модель данных Qt QML, похоже, не работает с переполнением стека

Я работал с примерами в http://doc.qt.digia.com/4.7/qdeclarativemodels.html это страница Qt в декларативных моделях данных QML. В частности, я работаю с objectlistmodel пример, который поставляется с Qt SDK (в examples / декларативном / modelviews / objectlistmodel). Кажется, все работает достаточно хорошо, пока я не попытаюсь объединить это с примером QMLPageControl в http://www.developer.nokia.com/Community/Wiki/How_to_create_a_Page_Control_component_in_QML.

Когда я пытаюсь отобразить основанную на 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 }

}
}
}

…все работает довольно хорошо. Это работает полностью, как и ожидалось — появляется окно с текстом на цветном фоне в полосах.

ListView, отображающий 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, отображающий QML ListModel

PathView, отображающий QML ListModel, в движении

Сделав резервную копию, я могу определить объект данных в 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 }

}
}

}

Еще раз, это работает просто отлично — появляется диалог с текстом на цветном фоне, упорядоченный по полосам. Кажется, что отображение ListView, поддерживаемого моделью C ++, работает каждый бит, а также отображение ListView, поддерживаемого QML ListModel.

ListView отображает QList в 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 в 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 ++-модулей. Например, документация объекта PathView на http://qt-project.org/doc/qt-4.8/qml-pathview.html не говорит, какие свойства должна поддерживать его модель. Более того, документация ListModel не является окончательной — в ней не указано, какие именно свойства поддерживает ListModel, и нет четкой документации о том, как точно QList удовлетворяет этим требованиям и как он этого не делает.

ОБНОВЛЕНИЕ: я пробовал это с Qt 5 на Windows, и у меня все еще есть та же проблема.

2

Решение

Оказывается, есть очень простая причина, по которой count собственность cppModel недоступно — это потому что ни QAbstractListModel ни QList<> иметь count имущество!

Я предполагал, что тот факт, что ListModel может быть заменен объектом на C ++, таким как QList<> означало, что они были полиморфными и что ListView или PathView будут использовать count свойство правильно обрабатывать их.

Во-первых, ни QAbstractListModel ни QList<> полиморфны с ListModel, Оказывается, что они все просто в специальном корпусе — ListView знает, есть ли у него ListModel или QList<> или QAbstractListModel и имеет отдельные пути кода для использования каждого. ListView не нуждается в несуществующем count свойство управлять QList<> или QAbstractListModel, На самом деле, мне не ясно, что ListView а также PathView даже использовать ListModel«s count имущество. count Свойство, кажется, в основном для программиста QML. В моем примере я использовал count свойство строить Path объект в PathView, Мой пример работает отлично, если я использую length свойство вместо этого, потому что QList<> Имеет ли length имущество.

Спасибо blam и torgeirl на # qt-qml за помощь в этом (ни один из них не хотел собирать баллы стекового потока, публикуя этот ответ, поэтому я публикую его на благо сообщества).

8

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]