Why VXYModelMapper doesn't work as expected ?
-
When I press a button , series have to be populated via VXYModelMapper.
But it doesn't happen.
Also I don't see function 'ChartDataModel::data' to be triggered.
But when create series manually I do see 'line series' on the chart itself.
Attaching QML file , model .h .cpp , main.cpp and cmake.
If smb would like to have a look.So the problem is when VXYModelMapper is used I don't see any charts
When I populate data manually ( see 'MANUAL CHART LOADING' function )
I do see data points.To be more specific, on the project with 'lazyload' it does work on Linux/Windows and Intel Mac.
( had the same warinings like '"Invalid X coordinate index in model mapper."' )
Aka by appeding points to model , but on M1 pro I faced an issue that I can't see any charts.
I simplified the issue , and it seemed that data is not loaded to the Charts itself.With this minimal example that I have added , it seems that it doesn't work on windows also.
Tried 6.9.0 on M1 and used 6.7.2 on Windows.import QtQuick import QtCharts import QtQuick.Window import QtQuick.Controls import QtQuick.Controls.Material import testChart 1.0 Window { id: mainWindow width: 640 height: 480 visible: true title: "Chart Example" ChartView { id: chart anchors.fill: parent antialiasing: true smooth: true ValueAxis { id: valueAxisY max: 10 } ValueAxis { id: valueAxisX max: 10 } } Component { id: mapperComponent VXYModelMapper {} } Connections { target: chartDataModel function onModelDataChanged() { var series = chart.createSeries(ChartView.SeriesTypeLine, "", valueAxisX, valueAxisY); series.color = "red"; series.width = 1; var mapper = mapperComponent.createObject(mainWindow, { series: series, model: chartDataModel, xColumn: chartDataModel.roleX, yColumn: chartDataModel.roleY }) } //DEBUG OUTPUT // function onModelDataChanged() { // var series = chart.createSeries(ChartView.SeriesTypeLine, "", valueAxisX, valueAxisY); // series.color = "red"; // series.width = 1; // console.log("Creating mapper object..."); // var mapper = mapperComponent.createObject(mainWindow); // if (!mapper) { console.error("Failed to create mapper object!"); return; } // console.log("Assigning series:", series); // mapper.series = series; // console.log("Assigning roles: X =", chartDataModel.roleX, " Y =", chartDataModel.roleY); // mapper.xColumn = chartDataModel.roleX; // mapper.yColumn = chartDataModel.roleY; // console.log("Assigning model:", chartDataModel); // mapper.model = chartDataModel; // console.log("Mapper configured:", mapper); // } //MANUAL CHART LOADING // function onModelDataChanged() { // var series = chart.createSeries(ChartView.SeriesTypeLine, "Data Series", valueAxisX, valueAxisY); // series.color = "red"; // series.width = 1; // console.log("Manually populating series..."); // var rowCnt = chartDataModel.rowCount(); // for (var i = 0; i < rowCnt; ++i) { // var point = chartDataModel.getPoint(i); // series.append(point.x, point.y); // } // console.log("Manual population complete."); // } } Button { anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom width: 200 height: 50 text: "Fill in Chart with Data" onClicked: chartDataModel.modelChanged() Material.elevation: 6 Material.background: Material.colorAccent Material.foreground: "white" font.pixelSize: 16 background: Rectangle { radius: 8 color: "blue" border.color: Material.primary border.width: 1 } } }
#ifndef CHARTDATAMODEL_H #define CHARTDATAMODEL_H #include <QAbstractListModel> #include <QList> #include <QPointF> struct DataPoint { qreal x; qreal y; }; class ChartDataModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(int roleX READ getRoleX CONSTANT) Q_PROPERTY(int roleY READ getRoleY CONSTANT) public: enum ColumnId { XRole = Qt::UserRole + 1, YRole }; Q_ENUM(ColumnId) explicit ChartDataModel(QObject *parent = nullptr); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; Q_INVOKABLE void modelChanged() { emit modelDataChanged(); } int getRoleX() const { return XRole; } int getRoleY() const { return YRole; } Q_INVOKABLE QPointF getPoint(int row) const; signals: void modelDataChanged(); private: QList<DataPoint> m_pointList; }; #endif // CHARTDATAMODEL_H
#include "chartdatamodel.h" #include "QDebug" ChartDataModel::ChartDataModel(QObject *parent) : QAbstractListModel(parent) { m_pointList.append({0.0, 0.0}); m_pointList.append({1.1, 2.1}); m_pointList.append({1.9, 3.3}); m_pointList.append({2.1, 2.1}); m_pointList.append({2.9, 4.9}); m_pointList.append({3.4, 3.0}); m_pointList.append({4.1, 3.3}); } int ChartDataModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); qDebug() << "ChartDataModel::rowCount() called, returning:" << m_pointList.size(); return m_pointList.size(); } QVariant ChartDataModel::data(const QModelIndex &index, int role) const { qDebug() << "ChartDataModel::data() called for row:" << index.row() << "role:" << role; if (!index.isValid() || index.row() < 0 || index.row() >= m_pointList.size()) { qDebug() << " -> Invalid index or row out of bounds"; return QVariant(); } const DataPoint &measurement = m_pointList.at(index.row()); if (role == XRole) { qDebug() << " -> Returning XRole:" << measurement.x; return measurement.x; } else if (role == YRole){ qDebug() << " -> Returning YRole:" << measurement.y; return measurement.y; } qDebug() << " -> Role not matched, returning invalid QVariant"; return QVariant(); } QPointF ChartDataModel::getPoint(int row) const { if (row >= 0 && row < m_pointList.size()) { return QPointF(m_pointList.at(row).x, m_pointList.at(row).y); } qWarning() << "ChartDataModel::getPoint requested invalid row:" << row; return QPointF(); // Return default QPointF }
#include <QApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "ChartDataModel.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); ChartDataModel chartDataModel; qmlRegisterType<ChartDataModel>("testChart", 1, 0, "ChartDataModel"); QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("chartDataModel", &chartDataModel); QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.loadFromModule("testChart", "Main"); return app.exec(); }
cmake_minimum_required(VERSION 3.16) project(testChart VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 REQUIRED COMPONENTS Charts Core Gui Qml Quick) qt_standard_project_setup(REQUIRES 6.5) qt_add_executable(apptestChart main.cpp ) qt_add_qml_module(apptestChart URI testChart VERSION 1.0 QML_FILES Main.qml SOURCES chartdatamodel.h chartdatamodel.cpp ) # Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. # If you are developing for iOS or macOS you should consider setting an # explicit, fixed bundle identifier manually though. set_target_properties(apptestChart PROPERTIES # MACOSX_BUNDLE_GUI_IDENTIFIER com.example.apptestChart MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} MACOSX_BUNDLE TRUE WIN32_EXECUTABLE TRUE ) target_link_libraries(apptestChart PRIVATE Qt::Charts PRIVATE Qt::Core PRIVATE Qt::Gui PRIVATE Qt::Qml PRIVATE Qt::Quick ) include(GNUInstallDirs) install(TARGETS apptestChart BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
QML debugging is enabled. Only use this in a safe environment. 2025-04-07 19:40:16.372 apptestChart[91733:30141818] +[IMKClient subclass]: chose IMKClient_Modern 2025-04-07 19:40:16.372 apptestChart[91733:30141818] +[IMKInputSession subclass]: chose IMKInputSession_Modern ChartDataModel::rowCount() called, returning: 7 initializeXYFromModel "Invalid X coordinate index in model mapper." ChartDataModel::rowCount() called, returning: 7 ChartDataModel::rowCount() called, returning: 7 initializeXYFromModel "Invalid X coordinate index in model mapper." ChartDataModel::rowCount() called, returning: 7 ChartDataModel::rowCount() called, returning: 7 ChartDataModel::rowCount() called, returning: 7 initializeXYFromModel "Invalid X coordinate index in model mapper."