Unable to test QT/QML model within model functionality to draw charts on UI.
Unsolved
QML and Qt Quick
-
Hello i'm trying to create a view where user can set individual count of chart in their respective item. Basically using nested model concept where the top model is just a layout and in inner model i'm creating a chart.
Here i'm attaching all the code for reference. I'm able to use outer model but inner model is not working.
Here i've attached full project source code
I'm using Qt 6.2 in Ubuntu environment.
Provide your suggestions.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 import "." 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) } 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) } Repeater { id: seriesRepeater property int rowIndex: index // model: chartRepeater.model[index].GraphParam model: monitoringScreen.graphModel.m_Items Component.onCompleted: { console.log("seriesRepeater", index, model) } // delegate: { // console.log("seriesRepeater model:", model); // if (model && model.length > 0 && model[0].GraphParam) { // console.log("seriesRepeater GraphParam:", model[0].GraphParam); // return ChartViewWidget { // paramTitle: model[0].GraphParam[0].GraphTitle // // Add other properties as needed // } // } else { // console.error("Invalid model data at index:", index); // return Item {} // Placeholder item to prevent errors // } // } delegate: ChartViewWidget { visible: true paramTitle: model.GraphTitle yaxisMinValue: -5 yaxisMaxValue: 5 Component.onCompleted: { console.log("ChartViewWidget", index) } } // delegate: Rectangle { // color: "red" // opacity: 0.6 // Layout.fillHeight: true // Layout.fillWidth: true // Component.onCompleted: { // console.log("Rectangle", index) // } // } } } } } }
ChartViewWidget.qml
/* This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only. It is supposed to be strictly declarative and only uses a subset of QML. If you edit this file manually, you might introduce QML code that is not supported by Qt Design Studio. Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files. */ import QtQuick 6.2 import QtQuick.Controls 6.2 import QtQuick.Layouts 1.3 import QtQuick.Controls.Universal 2.12 import QtCharts 2.5 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" } } Connections { target: chartType Component.onCompleted: { console.log("Chart Created") } } } }
graphmodel.cpp
#include "graphmodel.h" GraphModel::GraphModel(QObject* parent) : QAbstractListModel(parent) { } const QList<double> GraphModel::m_SampledData = { 0.0449999999999999, 0.0449999999999999, }; int GraphModel::rowCount(const QModelIndex& parent) const { qDebug() << "rowCount:" << m_Items.size(); if (parent.isValid()) return 0; return m_Items.size(); } QVariant GraphModel::data(const QModelIndex& index, int role) const { qDebug() << "data:" << index.row() << role; 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; GraphWidgetParam localGrWidget; 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()) { m_Items[row].GraphParam[colIndex].GraphTitle = title; // GraphWidgetParam* pParam = m_Items[row].GraphParam.at(colIndex); // if (pParam->GraphTitle != title) { // pParam->GraphTitle = title; // // qDebug() <<"Graph Title"<< 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()) { m_Items[row].GraphParam[colIndex].GraphDataValue = value; // GraphWidgetParam* pParam = m_Items[row].GraphParam.at(colIndex); // pParam->GraphDataValue = value; } } } // void GraphModel::addCharts(int paramId) //{ // int row = getModelParameterIndex(paramId); // if (row >= 0 && row < m_Items.size()) // { // GraphWidgetParam localWidget = {}; // m_Items[row].GraphParam.append(localWidget); // } // } 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) { qDebug() << "getModelParameterIndex:" << 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) { // StorageModelItem item; // int rows = rowCount(); 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; // y = m_SampledData.at(m_SampleIndex); // y = rand()%100; // y = m_Items.at(row).GraphParam.at(seriesIndex).GraphDataValue; // GraphWidgetParam* pParam = m_Items[row].GraphParam.at(seriesIndex); y = m_Items[row].GraphParam[seriesIndex].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 = m_Items[row].GraphParam[seriesIndex].yMin; double yMax = m_Items[row].GraphParam[seriesIndex].yMax; // double yMin = pParam->yMin; // double yMax = pParam->yMax; if (y > yMax) { yMax = y; yMax = yMax + (yMax * 0.3); // setData(index(row),yaxis_max,GraphModel::GraphYaxisMaxRole); // setYAxisMax(yaxis_max); } if (y < yMin) { yMin = y; yMin = yMin + (yMin * 0.3); yMin = yMin - yMax; // setData(index(row),yaxis_min,GraphModel::GraphYaxisMinRole); // setData(id,yaxis_min,GraphModel::GraphYaxisMinRole); // setYAxisMin(yaxis_min); } } void GraphModel::updateGraphData(int id, QList<int>& grData) { int row = -1; row = getModelParameterIndex(id); qDebug() << Q_FUNC_INFO << id << row; if (row != -1) { // m_Items[row].m_GraphData = grData; emit updateGraphToUi(row); } }
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) // Q_PROPERTY(QList<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; // return m_Items.at(index).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 addCharts(int paramId); void clearCharts(int paramId); void addNewGraphValue(int paramId, int colIndex, double value); void setGraphTitle(int paramId, const QString& title, int colIndex); // const QList<GraphWidgetParam> * grWidget(int id); // 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
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; // localGrWidget->GraphTitle = QString("%1-%2").arg(ParamType).arg(ChildGraph); // localGrWidget->setGraphTitle(QString("%1-%2").arg(ParamType).arg(ChildGraph)); GraphWidgetParam localGrWidget; localGrWidget.GraphTitle = QString("%1-%2").arg(ParamType).arg(ChildGraph); item.GraphParam.append(localGrWidget); } m_GraphModel->AppendModel(item); } GraphModel *MonitoringScreen::graphModel() const { return m_GraphModel; }
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
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "monitoringscreen.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); MonitoringScreen monitoringScreen; QQmlApplicationEngine engine; const QUrl url(u"qrc:/test_graph/Main.qml"_qs); qRegisterMetaType<GraphWidgetParam>("GraphWidgetParam"); // qmlRegisterType<GraphModel>("model.trial", 1, 0, "GraphModel1"); engine.rootContext()->setContextProperty( "monitoringScreen", &monitoringScreen); engine.load(url); return app.exec(); }