Qt QML数据模型似乎不工作与C ++ [英] Qt QML data model doesn't seem to work with C++
问题描述
我一直在使用不会说明其模型需要支持的属性。此外,ListModel文档不是确定的 - 它没有明确列出ListModel支持什么属性,没有明确的文档,如何精确地QList满足这些要求,以及它不是。
更新:我在Windows上尝试使用Qt 5,我仍然有同样的问题。
事实证明,有一个非常简单的原因, cppModel
的 count
- 这是因为 QAbstractListModel
或 QList<>
都有计数
property!
我假设可以用基于C ++的对象替换 ListModel
像QList<>意味着它们是多态的,并且ListView或PathView将使用 count
属性来正确地处理它们。
首先, QAbstractListModel
或 QList<>
与 ListModel
是多态的。事实证明,它们都只是特殊的 - ListView
知道它是否有一个 ListModel
或一个 QList<>
或 QAbstractListModel
,并且具有用于使用每个的单独代码路径。 ListView
不需要不存在的 count
属性来管理 QList< / code>或
QAbstractListModel
。事实上,我不清楚 ListView
和 PathView
甚至使用 ListModel
' count
属性。 count
属性似乎主要是为了QML程序员的好处。在我的例子中,我使用 count
属性在 PathView中构建一个
。如果我使用路径
length
属性,因为 QList<>
DOES有一个 length
属性。
感谢#qt-qml上的blam和torgeirl帮我解决这个问题发布此答案,所以我发布它的社区的利益)。
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.
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.
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.
Backing up, I can then define a data object in C++ like this:
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();
}
}
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();
}
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 }
}
}
}
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.
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
}
}
}
}
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
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.
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.
UPDATE: I've tried this with Qt 5 on Windows, and I'm still having the same problem.
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!
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.
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.
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屋!