Issue While Using Repeater inside Repeater in Qml.
-
Hello Everyone!
I have used two repeater model first one is for chart and second for series and thats are coming from graphmodel.cpp.
I am currently facing an issue with connecting a second model(SeriesRepeater Model) in main.qml file
I have written model.GraphParam in SeriesRepeater Model. It does not seem to link properly with backend. Any guidance on resolving this would be grateful. Thankyou!Main.qml
import QtQuick import QtQuick.Window import QtQuick 6.2 import QtQuick.Controls 6.2 import QtQuick.Layouts 1.3 import QtCharts 2.5 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") GridLayout { id: viewGridLayout anchors.fill: parent anchors.margins: 10 columns: 2 rows: 4 columnSpacing: 10 rowSpacing: 10 flow: GridLayout.LeftToRight Layout.leftMargin: 3 Layout.rightMargin: 0 Layout.topMargin: 3 Layout.bottomMargin: 3 Repeater { id: chartRepeater model: monitoringScreen.graphModel Component.onCompleted: { console.log("chartRepeater", model, model.length) // Iterate over the model and print details of each item for (var i = 0; i < model.length; i++) { var item = model[i] console.log("Item", i, ":", JSON.stringify(item)) } } delegate: ColumnLayout { id: chartRepeaterColumnLayout Layout.fillHeight: true Layout.fillWidth: true Layout.row: 0 + index Layout.column: 0 spacing: 1 Component.onCompleted: { console.log("chartRepeaterColumnLayout", index, model.GraphMaximumCount) } Repeater { id: seriesRepeater property int rowIndex: index model: model.GraphParam Component.onCompleted: { console.log("seriesRepeater", index, model) } delegate: ChartViewWidget { visible: true paramTitle: "Hello" yaxisMinValue: -5 yaxisMaxValue: 5 Component.onCompleted: { console.log("ChartViewWidget", index) } } } } } } }
ChartViewWidget.qml
import QtQuick 6.2 import QtQuick.Controls 6.2 import QtQuick.Layouts 1.3 import QtQuick.Controls.Universal 2.12 import Qt5Compat.GraphicalEffects import QtQuick.Shapes 1.5 import QtCharts 2.15 RowLayout { id: chartviewRowLayout Layout.fillHeight: true Layout.fillWidth: true spacing: 0 property alias paramTitle: paramTitleText.text property alias yaxisMinValue: yAxisLineSeries.min property alias yaxisMaxValue: yAxisLineSeries.max property alias chartWidget: chartType Rectangle { Layout.fillHeight: true Layout.minimumWidth: 50 color: "#1d2027" Text { id: paramTitleText anchors.fill: parent color: "#048E93" horizontalAlignment: Text.AlignRight verticalAlignment: Text.AlignVCenter textFormat: Text.RichText } } Rectangle { Layout.fillHeight: true Layout.fillWidth: true color: "#1d2027" ChartView { id: chartType enabled: true smooth: true backgroundRoundness: 0 legend.visible: false plotAreaColor: "#1d2027" backgroundColor: "#1d2027" margins.top: 0 margins.bottom: 0 margins.right: 3 margins.left: 0 anchors.fill: parent LineSeries { id: lineSeries axisX: xAxisLineSeries axisY: yAxisLineSeries color: "#048E93" } ValuesAxis { id: xAxisLineSeries min: 0 max: 500 gridVisible: false tickCount: 3 visible: false } ValuesAxis { id: yAxisLineSeries min: -1 max: 1 gridVisible: false tickCount: 3 labelsColor: "#999999" } } } }
graphModel.h
#ifndef GRAPHMODEL_H #define GRAPHMODEL_H #include <QAbstractAxis> #include <QAbstractListModel> #include <QObject> #include <QString> #include <QXYSeries> #include <QtCharts> struct GraphWidgetParam { QString GraphTitle; QList<double> GraphData; double GraphDataValue; double yMin; double yMax; int CurrentIndex; }; struct GraphModelItem { int MaximumCount; int CursorSize; QList<GraphWidgetParam*> GraphParam; int id; }; class GraphModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(GraphWidgetParam* grWidget READ grWidget NOTIFY grWidgetChanged) public: enum GraphModelRole { GraphTitleRole = Qt::UserRole + 1, GraphPointRole, GraphMaximumCountRole, GraphCursorSizeRole, GraphListRole, ParameterId }; Q_ENUM(GraphModelRole) // Q_INVOKABLE GraphWidgetParam* getGraphParam(int index) const { // if (index < 0 || index >= graphItems.count()) { // return nullptr; // } // GraphModelItem parame; //// GraphWidgetParam * pParam = m_Items[0].GraphParam.at(0); // return parame.GraphParam.at(0); // Assuming you want the first GraphParam in the list // } explicit GraphModel(QObject* parent = nullptr); int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QVector<GraphModelItem> m_Items; QHash<int, QByteArray> roleNames() const override; bool setData(const QModelIndex& index, const QVariant& value, int role) override; int getModelParameterIndex(int id); void updateParameterValuesOnModel(int id, GraphModelItem& item, const QString& valueStr); void startDataChange(void); void updateDataChange(void); void updateGraphData(int id, QList<int>& grData); void clearCharts(int paramId); void addNewGraphValue(int paramId, int colIndex, double value); void setGraphTitle(int paramId, const QString& title, int colIndex); GraphWidgetParam* grWidget(); void appendRow(void); void endAppend(void); void AppendModel(GraphModelItem & item); public slots: void updateGraphSeriesDataFromIndex(int id, int seriesIndex, QAbstractSeries* series); signals: void updateGraphToUi(int index); void grWidgetChanged(); private: static const QList<double> m_SampledData; int m_SampleIndex = 0; int m_index = 0; int m_TotalCount = 0; int cursorSize = 5; qreal qMultiplier = 1; GraphWidgetParam m_GraphWidgetParam; QList<GraphModelItem*> graphItems; }; #endif // GRAPHMODEL_H
graphmodel.cpp
#include "graphmodel.h" GraphModel::GraphModel(QObject* parent) : QAbstractListModel(parent) { } int GraphModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return m_Items.size(); } QVariant GraphModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() < 0 || index.row() >= m_Items.size()) { return QVariant(); } switch (role) { case GraphMaximumCountRole: return QVariant(m_Items.at(index.row()).MaximumCount); case GraphCursorSizeRole: return QVariant(m_Items.at(index.row()).CursorSize); case GraphListRole: return QVariant::fromValue(m_Items.at(index.row()).GraphParam[0]); // return QVariantConstPointer(m_Items.at(index.row()).GraphParam[0]); // return QVariant(m_Items.at(index.row()).GraphParam[0]); case ParameterId: return QVariant(m_Items.at(index.row()).id); default: return QVariant(); } } QHash<int, QByteArray> GraphModel::roleNames() const { QHash<int, QByteArray> names; names[GraphTitleRole] = "GraphTitle"; names[GraphMaximumCountRole] = "GraphMaximumCount"; names[GraphCursorSizeRole] = "GraphCursorSize"; names[GraphListRole] = "GraphList"; names[ParameterId] = "id"; return names; } bool GraphModel::setData(const QModelIndex& index, const QVariant& value, int role) { int row = index.row(); bool isValid = false; qDebug() << Q_FUNC_INFO; if (row >= 0 && row < m_Items.size()) { switch (role) { case ParameterId: if (m_Items[row].id != value.toInt()) { m_Items[row].id = value.toInt(); isValid = true; } break; case GraphMaximumCountRole: if (m_Items[row].MaximumCount != value.toInt()) { m_Items[row].MaximumCount = value.toInt(); isValid = true; } break; case GraphCursorSizeRole: if (m_Items[row].CursorSize != value.toInt()) { m_Items[row].CursorSize = value.toInt(); isValid = true; } break; case GraphListRole: qDebug() << Q_FUNC_INFO << "GraphListRole" << row << value.toInt(); if (m_Items[row].GraphParam.size() != value.toInt()) { m_Items[row].GraphParam.clear(); for (int i = 0; i < value.toInt(); i++) { GraphWidgetParam* localGrWidget = new GraphWidgetParam; m_Items[row].GraphParam.append(localGrWidget); } isValid = true; } break; default: break; } if (isValid == true) emit dataChanged(index, index, QVector<int>() << role); } return true; } void GraphModel::setGraphTitle(int paramId, const QString& title, int colIndex) { int row = getModelParameterIndex(paramId); if (row >= 0 && row < m_Items.size()) { if (colIndex >= 0 && colIndex < m_Items[row].GraphParam.size()) { GraphWidgetParam* pParam = m_Items[row].GraphParam.at(colIndex); if (pParam->GraphTitle != title) { pParam->GraphTitle = title; } } } } void GraphModel::addNewGraphValue(int paramId, int colIndex, double value) { int row = getModelParameterIndex(paramId); if (row >= 0 && row < m_Items.size()) { if (colIndex >= 0 && colIndex < m_Items[row].GraphParam.size()) { GraphWidgetParam* pParam = m_Items[row].GraphParam.at(colIndex); pParam->GraphDataValue = value; } } } void GraphModel::clearCharts(int paramId) { int row = getModelParameterIndex(paramId); if (row >= 0 && row < m_Items.size()) { m_Items[row].GraphParam.clear(); } } int GraphModel::getModelParameterIndex(int id) { if (m_Items.size()) { for (int i = 0; i < m_Items.size(); i++) { if (m_Items.at(i).id == id) { return i; } } } return -1; } void GraphModel::appendRow(void) { int rows = rowCount(); beginInsertRows(QModelIndex(), rows, rows); } void GraphModel::endAppend(void) { endInsertRows(); } void GraphModel::AppendModel(GraphModelItem & item) { appendRow(); m_Items.append(item); endAppend(); } void GraphModel::startDataChange(void) { beginResetModel(); } void GraphModel::updateDataChange(void) { endResetModel(); } void GraphModel::updateGraphSeriesDataFromIndex(int id, int seriesIndex, QAbstractSeries* series) { if (series == nullptr) return; QXYSeries* xySeries = static_cast<QXYSeries*>(series); if (xySeries == nullptr) return; qreal x(0); qreal y(0); int row = getModelParameterIndex(id); x = xySeries->count(); m_TotalCount = m_Items.at(row).MaximumCount; qDebug() << "Total Count" << m_TotalCount; GraphWidgetParam* pParam = m_Items[row].GraphParam.at(seriesIndex); y = pParam->GraphDataValue; if (m_SampleIndex < (m_TotalCount - 4)) { m_SampleIndex += 2; } else { m_SampleIndex = 0; } if (xySeries->count() < m_TotalCount) { xySeries->append(x, y); qDebug() << "x:y:" << x << y; // qDebug() << "XY Point count:" << xySeries->count(); } else { if ((m_index <= (m_TotalCount - cursorSize))) { xySeries->removePoints(m_index, cursorSize); xySeries->insert(m_index, QPointF(m_index, y)); xySeries->insert(m_index + 1, QPointF(m_index + 1, 0)); xySeries->insert(m_index + 2, QPointF(m_index + 2, 0)); xySeries->insert(m_index + 3, QPointF(m_index + 3, 0)); xySeries->insert(m_index + 4, QPointF(m_index + 4, 0)); QList<QPointF> points1 = xySeries->points(); points1[m_index + 1].setY(NAN); points1[m_index + 2].setY(NAN); points1[m_index + 3].setY(NAN); points1[m_index + 4].setY(NAN); xySeries->replace(points1); } if ((m_index < (m_TotalCount - 1))) { m_index++; } else { m_index = 0 + 1; qMultiplier++; if (qMultiplier > 5) { qMultiplier = 1; } } } double yMin = pParam->yMin; double yMax = pParam->yMax; if (y > yMax) { yMax = y; yMax = yMax + (yMax * 0.3); } if (y < yMin) { yMin = y; yMin = yMin + (yMin * 0.3); yMin = yMin - yMax; } } void GraphModel::updateGraphData(int id, QList<int>& grData) { int row = -1; row = getModelParameterIndex(id); qDebug() << Q_FUNC_INFO << id << row; if (row != -1) { emit updateGraphToUi(row); } } GraphWidgetParam* GraphModel::grWidget(void) { GraphWidgetParam* pParam = m_Items[0].GraphParam.at(0); return pParam; }
MonitoringScreen.cpp
#include "monitoringscreen.h" #include "graphmodel.h" MonitoringScreen::MonitoringScreen(QObject *parent) : QObject{parent} { m_GraphModel = new GraphModel(this); initMonitoringGraph(1,2); initMonitoringGraph(2,1); initMonitoringGraph(3,2); } MonitoringScreen::~MonitoringScreen() { delete m_GraphModel; } void MonitoringScreen::initMonitoringGraph(int ParamType, int ChildGraph) { GraphModelItem item; item.id = ParamType; item.MaximumCount = ChildGraph; for (int i = 0; i < ChildGraph; i++) { GraphWidgetParam* localGrWidget = new GraphWidgetParam; item.GraphParam.append(localGrWidget); } m_GraphModel->AppendModel(item); } GraphModel *MonitoringScreen::graphModel() const { return m_GraphModel; }
-
@hemang_1711 said in Issue While Using Repeater inside Repeater in Qml.:
... id: seriesRepeater property int rowIndex: index model: model.GraphParam ...
In
model.GraphParam
what ismodel
and how isGraphParam
exposed from it (and what is it)? -
@Bob64 Thanks for replying...
- As I have mentioned I am using Repeater inside Repeater its chartviewrepeater model. thats why I am using model.GraphParam (monitoringScreen.graphModel.GraphParam).
- GraphParam is pointer of GraphWidgetParam structure which is availale in graphmodel.h.
- There is initMonitoringGraph fun in monitoringscreen.cpp I am using graphmodel here.
-
@hemang_1711 thanks. My apologies if I missed anything but there is quite a lot of code to navigate through.
Firstly, I am not sure whether the QML scoping rules allow you refer to
model
fromchartRepeater
whenmodel
fromseriesRepeater
is in scope.It might be better to specify the RHS explicitly at least to rule out any issue.
Secondly, although I now see that
GraphParam
is a member ofGraphModelItem
, it is not clear to me thatGraphModelItem
has been exposed to QML. Again, apologies if I have missed something. (Also, I guess there might be other code that hasn't been shown.) -
@Bob64
As you said "QML scoping rules allow you refer to model from chartRepeater when model from seriesRepeater is in scope." And About Series model I print in Console window onComponent.on Completed.
There is monitoringscreen.h i not provided.monitoringscreen.h
#ifndef MONITORINGSCREEN_H #define MONITORINGSCREEN_H #include <QObject> #include "graphmodel.h" class MonitoringScreen : public QObject { Q_OBJECT Q_PROPERTY(GraphModel* graphModel READ graphModel NOTIFY graphModelChanged) public: explicit MonitoringScreen(QObject *parent = nullptr); ~MonitoringScreen(); GraphModel *graphModel() const; signals: void graphModelChanged(); private: void initMonitoringGraph(int ParamType, int ChildGraph); GraphModel *m_GraphModel = nullptr; }; #endif // MONITORINGSCREEN_H
-
@hemang_1711 I am not sure why it is not working for you. If I were you I would try to cut it down to the smallest example possible (no need to involve charts or anything) to investigate how to get a nested model to work. I am reasonably sure it is possible because I have seen people discuss it, but I have looked through my own code and have never needed to do this. I might try to make a simple project myself.
-
@hemang_1711 I have just gone back to your original post and I see again what originally confused me.
If you recall, I asked about
GraphParam
, which you are trying to access in your QML. I looked for this in your model implementation, but your model does not have a role"GraphParam"
.You do have a role
"GraphList"
, which seems to return the first element of the list member namedGraphParam
in theGraphModelItem
struct in your implementation. AlthoughGraphParam
is the name of the struct member, QML does not know anything about this name. It only sees the names you have defined in your roles.