Я работал с примерами в 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 }
}
}
}
…все работает довольно хорошо. Это работает полностью, как и ожидалось — появляется окно с текстом на цветном фоне в полосах.
Затем я могу сделать что-то более сложное, например, использовать 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
}
}
}
}
Опять же, все это работает, как и ожидалось — появляется всплывающее окно с перетаскиваемым списком цветных блоков.
Сделав резервную копию, я могу определить объект данных в 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.
То, что я хотел бы получить, — это модель 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.
И на консоли отладки я вижу это:
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, и у меня все еще есть та же проблема.
Оказывается, есть очень простая причина, по которой 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 за помощь в этом (ни один из них не хотел собирать баллы стекового потока, публикуя этот ответ, поэтому я публикую его на благо сообщества).
Других решений пока нет …