Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QML Repeater with Qt Graphs Invalid Y Values
Forum Updated to NodeBB v4.3 + New Features

QML Repeater with Qt Graphs Invalid Y Values

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
qabstractmodelqml c++qmlqt graphsrepeater
3 Posts 2 Posters 147 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    daviddev
    wrote last edited by daviddev
    #1

    I'm trying to have a TableModel work in Qt Graphs work with a QML Repeater. The graph works correctly when I comment out the Repeater and uncomment the included non-repeater version in QML. However when the Repeater is present, the model throws the error

    initializeXYFromModel Invalid Y coordinate index in model mapper.
    file:<filepath-to-qml/RepeaterPlot.qml:49:17: Unable to assign QString to qlonglong
    

    an equal amount of times to the number specified in the model property.

    All of this makes me think this is a QML problem rather than a model/C++ problem. I have hard coded all of the source file values for forum purposes. I'm using Qt 6.9.3 on windows 10.

    Would anyone have a hunch why the Y value column is not working no matter what I do and/or have suggestions for fixing it?

    //QML
    import QtQuick
    import QtGraphs
    import MyImport
    GraphsView {
        id: graphsViewRoot
        anchors.fill: parent
        axisX: ValueAxis {
            id: xAxis
            min: -10
            max: 260
        }
        axisY: ValueAxis {
            id: yAxis
            min: -60
            max: 60
        }
        Repeater {
            model: 2
            parent: graphsViewRoot
            delegate: Item {
                // Define the LineSeries instance
                LineSeries {
                    id: lineSeries1
                    name: "Data Series " //+ (model.index + 1)
                }
                // Define the XYModelMapper instance
                XYModelMapper {
                    model: MyRepeaterModel
                    series: lineSeries1
                    xSection: 0
                    ySection: model.index + 1
                }
            }
        }
    /* ///////////////////////////////////////////////////////////////////
    ////////////////THIS WORKS BY ITSELF/////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
         XYModelMapper {
             model: MyRepeaterModel
             series: lineSeries1     
             xSection: 0
             ySection: 1
         }
    
        LineSeries {
            id: lineSeries1
            name: "Data Series 1"
        }
    */
    }
    
    
    ////mainwindow and QML exposure
        myRepeaterModel = new RepeaterModel();
        qmlRegisterSingletonInstance("MyImport", 1, 0, "MyRepeaterModel",myRepeaterModel);
    
    
    //Source
    #include "RepeaterModel.hpp"
    #include <iostream>
    
    RepeaterModel::RepeaterModel(QObject *parent)
        : QAbstractTableModel(parent){
        mySpecStruct = {};
    }
    
    int RepeaterModel::rowCount(const QModelIndex &parent) const{
        if (parent.isValid())
            return 0;
        return 64;
    }
    int RepeaterModel::columnCount(const QModelIndex &parent) const{
        if (parent.isValid())
            return 0;
        return 3;
    }
    QHash<int, QByteArray> RepeaterModel::roleNames() const{
        QHash<int, QByteArray> roles;
        roles[XRole] = "xPos";
        roles[YRole] = "yPos";
        return roles;
    }
    
    QVariant RepeaterModel::data(const QModelIndex &index, int role) const{
        if (!index.isValid())
            return QVariant();
        int row = index.row();
        int col = index.column();
        if (role == Qt::DisplayRole) {
            if (col == 0) {
                return row;
            } else if (col == 1) {
                return 2;
            } else if (col == 2) {
                return 3;
            }
        }
        return QVariant();
    }
    
    ////header
    #ifndef RepeaterModel_HPP
    #define RepeaterModel_HPP
    
    #include <QAbstractTableModel>
    class RepeaterModel : public QAbstractTableModel
    {
        Q_OBJECT
        enum MyRoles {
            XRole = Qt::UserRole + 1,
            YRole
        };
    public:
        explicit RepeaterModel(QObject *parent = nullptr);
    
        // Basic functionality:
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
        int columnCount(const QModelIndex &parent = QModelIndex()) const override;
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
        QHash<int, QByteArray> roleNames() const override;
    
        void SetSpectrumData(ftStruct& specStruct);
        ftStruct getSpectrumData() const;
    
    signals:
        void spectrumChanged();
    
    private:
        ftStruct mySpecStruct;
    };
    
    #endif // RepeaterModel_HPP
    
    
    1 Reply Last reply
    0
    • A Offline
      A Offline
      Alouette
      wrote last edited by
      #2

      Repeater cannot be used to add LineSeries to a GraphsView. LineSeries is not a visual Item (not a QML Item), and GraphsView does not process its QML children. As a result, series created by Repeater are either never instantiated correctly or never registered with the graph.

      The correct solution is to use Instantiator and explicitly call GraphsView.addSeries().

      Instantiator is intended for exactly this case: creating non-visual objects and manually attaching them.

      Your code below is the correct and supported approach:

      import QtQuick
      import QtQuick.Controls.Basic
      import QtQuick.Controls 6.5
      import QtGraphs
      import Qt.labs.qmlmodels
      
      Item {
          id: processPlot
          property var model: TableModel  {
              id: seriesModel
              TableModelColumn { display: "time" }
              TableModelColumn { display: "raw_pressure" }
              TableModelColumn { display: "filtered_pressure" }
              TableModelColumn { display: "raw_position" }
              TableModelColumn { display: "filtered_position" }
              TableModelColumn { display: "raw_speed" }
              TableModelColumn { display: "filtered_speed" }
      
              rows: [
                  {
                      time: 0,
                      raw_pressure: 0,
                      filtered_pressure: 0,
                      raw_position: 240000,
                      filtered_position: 240000,
                      raw_speed: 0,
                      filtered_speed: 0,
                  },
                  {
                      time: 10,
                      raw_pressure: 5,
                      filtered_pressure: 4,
                      raw_position: 240400,
                      filtered_position: 240400,
                      raw_speed: 20,
                      filtered_speed: 18,
                  },
                  {
                      time: 20,
                      raw_pressure: 10,
                      filtered_pressure: 9,
                      raw_position: 241000,
                      filtered_position: 241000,
                      raw_speed: 20,
                      filtered_speed: 19,
                  }
              ]
          }
      
          GraphsView {
              id: graphsView
              anchors.fill: parent
              axisX: ValueAxis {
                  max: 100
              }
              axisY: ValueAxis {}
      
          }
      
          Instantiator  {
              model: 6
              Component.onCompleted: {
                  console.log("Repeater completed");
              }
      
              delegate: LineSeries {
                  id: series
                  Component.onCompleted: {
                      console.log("Repeated item completed");
                      graphsView.addSeries(series);
                  }
                  XYModelMapper {
                      model: processPlot.model
                      series: series
                      xSection: 0
                      ySection: index + 1
                  }
                  Component.onDestruction: graphsView.removeSeries(series)
              }
          }
      }
      
      
      1 Reply Last reply
      0
      • D Offline
        D Offline
        daviddev
        wrote last edited by
        #3

        Thank you very much for looking at this in the first place. The Initializer is an unfamiliar Component I'll be using better. The TableModel however, is something I cannot use.

        When your provide code works runs by itself, it doesn't produce the error. However, the reason for the initializeXYModel is tied to QAbstractTableModel, not the Repeater or the Instantiator . When I run the XYModelMapper with the TableModel from the Qt.labs.qmlmodels as the model, the error disappears. However, when I use the QAbstractTableModel, the error is thrown with either the Repeater or the Instantiator .

        Is there a way to have the Instantiator or Repeater work with the QAbstractTableModel as the model property to your knowledge?

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved