LineSeries with QAbstractListModel's roles
-
I don't think SplineSeries takes a model. You are right DelegateModel maps a model to a model. You want something that can read a model and instance objects in the SplineSeries:
import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 import QtCharts 2.15 import QtQml.Models 2.12 ApplicationWindow { visible: true width: 400 height: 900 title: qsTr("Dynamic Charts") ListModel { id: listModel ListElement {xv:0; yv:0} ListElement {xv:0.25; yv:0.10} ListElement {xv:0.25; yv:0.25} ListElement {xv:0.50; yv:0.50} } Column { width: parent.width ChartView { width: parent.width height: 300 antialiasing: true legend.visible: false Instantiator { model: listModel onObjectAdded: splineseries.insert(index, object.x, object.y) onObjectRemoved: splineseries.remove(index) QtObject{ property real x: xv property real y: yv } } SplineSeries { id: splineseries } } } //Component.onCompleted: console.log(listModel.count) }
I tried a Repeater inside the SplineSeries, but it would not create items for whatever reason. Unsure why. I don't think the SplineSeries liked the Repeater.
-
@fcarney I did get your example code to work, but expanding that to my problem seems a bit unfeasible. I provided my "trivial" example, but in the real world I have almost 100 roles. It seems that I'd have to create a property in the
QtObject
that was in yourInstantiator
for each one of my roles.I'm really just looking for something that works somewhat like the example I provided originally, because there's actually a 3d charting QML object that does do it via roles, exactly the way I want, except in 3d and not 2d:
Scatter3D { anchors.fill: parent Scatter3DSeries { ItemModelScatterDataProxy { itemModel: itemModel xPosRole: "receivedTime" // Item roles from the original code I provided yPosRole: "val1" zPosRole: "val2" } } }
I'd really like essentially what is above, but in 2d chart form. I'm not sure why QML provides these objects for their 3d charting library, but not the 2d one.
-
You correctly identified the problem that VXYModelMapper works with model with columns and your model has multiple roles instead of columns.
If you don't want to modify your model to also add columns, you could write a proxy model transposing roles to columns as a middle man. For inspiration, the reverse has been done there : https://github.com/KDAB/KDToolBox/tree/master/qt/model_view/sortProxyModel
-
@GrecKo Thanks GrecKo for the inspiration for that. I created my own
QIdentityProxyModel
(wasn't sure if I should use that one, orQAbstractProxyModel
) as follows:class TrivialTableProxyModel: public QIdentityProxyModel { Q_OBJECT QML_ELEMENT public: TrivialTableProxyModel(QObject* parent = nullptr) : QIdentityProxyModel(parent) {}; virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override { if(!index.isValid()) { return {}; } if(role != Qt::DisplayRole) { return {}; } qDebug() << "Proxy:" << index << ", Role:" << role; return sourceModel()->data(createIndex(index.row(), 0), index.column() + Qt::UserRole + 1); // Adding Qt::UserRole+1 since that's where my roles start }
And in QML I implemented it as follows:
ChartView { anchors.fill: parent antialiasing: true legend.visible: true ScatterSeries { name: "Data" axisX: DateTimeAxis { } axisY: ValueAxis { } VXYModelMapper { xColumn: 0 // Received time role/column yColumn: 1 // Var1 role/column model: trivialTableProxyModel // Assume this was inserted into the root context } } }
It seems like it's much closer (I even got it working with manually setting the
VXYModelMapper
's rowCount), but when I leave it at the default -1, it seems to endlessly call thedata
function. I even went through the effort of turning my original model into aQAbstractTableModel
, but with the same result. Here's an output of the print statements from the proxy'sdata
function and the model'sdata
function:Proxy: QModelIndex(1,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 0 Model: QModelIndex(1,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 1 Proxy: QModelIndex(1,1,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 0 Model: QModelIndex(1,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 1 Proxy: QModelIndex(2,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 0 Model: QModelIndex(2,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 1 Proxy: QModelIndex(2,1,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 0 Model: QModelIndex(2,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 1 ... Proxy: QModelIndex(12065,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 0 Model: QModelIndex(12065,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 1 Proxy: QModelIndex(12065,1,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 0 Model: QModelIndex(12065,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 1 Proxy: QModelIndex(12066,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 0 Model: QModelIndex(12066,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 1 Proxy: QModelIndex(12066,1,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 0 Model: QModelIndex(12066,0,0x0,HousekeepingTableProxyModel(0x399856f580)), Role: 1
It may be hard to decipher, but the translation is working from roles/columns. I'm just now not sure why
VXYModelMapper
endlessly calls the data functions with ever increasing row counts. Is this a bug, or did I implement my model incorrectly? -
@Tyrannic said in LineSeries with QAbstractListModel's roles:
ScatterSeries
I don't see a dataProxy in the ScatterSeries docs like I see in the Scatter3DSeries. I don't see any docs that a ScatterSeries takes a model. How is this supposed to work?
-
Anyway, I may have a way to do go wide on your data. But I am unsure if this fits your data. I don't have a good feel for what is in your model:
import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Window 2.12 import QtCharts 2.15 import QtQml.Models 2.12 ApplicationWindow { visible: true width: 400 height: 900 title: qsTr("Dynamic Charts") ListModel { id: listModel ListElement {xv1:0.00; yv1:0.00; xv2:0.10; yv2:0.10; xv3:0.25; yv3:0.10; xv4:0.10; yv4:0.25} ListElement {xv1:0.50; yv1:0.50; xv2:0.75; yv2:0.50; xv3:0.50; yv3:0.75; xv4:1.00; yv4:1.00} } Column { width: parent.width ChartView { width: parent.width height: 300 antialiasing: true legend.visible: false Instantiator { model: listModel onObjectAdded: { for(var subindex=0; subindex<8; ++subindex){ console.log(index*8+subindex) splineseries.insert(index*8+subindex, object.points[subindex].x, object.points[subindex].y) } } onObjectRemoved: { for(var subindex=0; subindex<8; ++subindex){ splineseries.remove(index*8+subindex) } } delegate: QtObject{ property var points: { var arr = [] arr.push(Qt.point(xv1, yv1)) arr.push(Qt.point(xv2, yv2)) arr.push(Qt.point(xv3, yv3)) arr.push(Qt.point(xv4, yv4)) return arr } } } SplineSeries { id: splineseries } } } }
-
@fcarney Well, that was somewhat the point, was that it was frustrating that the
Scatter3dSeries
could take a roles as demonstrated by my example code, but not theScatterSeries
. Either way, I'm one step closer to having a solution thanks to @GrecKo, but as illustrated by my last post,VXYModelMapper
seems to be misbehaving whenrowCount
is -1. That or I messed up the Proxy and/or model. -
For checking your model put this in your models constructor:
new QAbstractItemModelTester(this, QAbstractItemModelTester::FailureReportingMode::Warning, this);
This will print out issues it finds. You can look at the source code to that class to see exactly what it is testing in the Qt source.
-