Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. displaying a C++ QChart in a QML ChartView delegate

displaying a C++ QChart in a QML ChartView delegate

Scheduled Pinned Locked Moved Solved General and Desktop
6 Posts 2 Posters 2.3k 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.
  • devDawgD Offline
    devDawgD Offline
    devDawg
    wrote on last edited by
    #1

    Hello all,

    I am looking to visually display several real-time QCharts that are updated with simulation data. I should have no problem with this portion; what I am confused about is the C++/QML interface.

    Disclaimer: I am using Qt 5.9.3 for a specific device.

    I have read through this LineChart example: https://doc.qt.io/qt-5.11/qtcharts-linechart-example.html

    And also the ChartView documentation: https://doc.qt.io/qt-5.11/qml-qtcharts-chartview.html

    My current approach is to use the following class as a context property:

    #include <QtCharts>
    #include <QLineSeries>
    #include <QProcess>
    #include <QQmlComponent>
    #include <QList>
    #include <QStringList>
    #include <QString>
    
    /*This class will be responsible for one specific module. Depending on the page, this model will contain a select number of params.
     * For example, on the summary page, we only want a brief overview of Priority 1 measurements, so the data models will be less compact.
     * Whereas on the following pages that detail full modules, the models will be larger.
     */
    
    
    class DataModel: public QObject
    {
    
        friend class QAbstractListModel;
    
        Q_OBJECT
    
    
    public:
        explicit DataModel(QObject * parent = nullptr);
        explicit DataModel(const QString file); //this is our main constructor here.
        explicit DataModel(DataModel&&); //move constructor
        explicit DataModel(const DataModel&); //copy constructor
    
        DataModel& operator=(const DataModel&);
        DataModel& operator=(DataModel&&);
    
        Q_INVOKABLE QString getTextBodyAt(int i);
        Q_INVOKABLE DataModule *getModuleAt(int i);
        Q_INVOKABLE int getModulesLength() { return modules.length(); }
        Q_INVOKABLE int getGraphsLength() { return graphs.length(); }
        Q_INVOKABLE DataPiece *getDataAt(int index) const;
        Q_INVOKABLE QLineSeries* getSeriesAt(int index) const {return series.at(index);}
        Q_INVOKABLE int getDataCount();
    
        int timeToSeconds(QTime* time) const;
        void addModule(DataModule* mod_);
        void addDataGraph(DataPiece* piece);
        void replaceDataGraph(DataPiece* piece, int index); //replaces the graph at the given index with a new graph for the supplied DataPiece.
        void removeDataGraphAt(int i); //removes the graph at the given index.
        const QVector<DataModule*> getModel() const;  
        const QVector<DataPiece*> getGraphs() {return graphs;}
        const QVector<QLineSeries*> getSeries() {return series;}
        const QVector<QTime*> getTimes() {return timers;}
    
        ~DataModel();
    signals:
        void pieceChanged(DataPiece*); //this signal might not be used anywhere.
        void pieceAdded(DataPiece*);
        void pieceReplaced(DataPiece*);
    
    public slots:
        void onClose();
        void on_pieceAdded(DataPiece *piece);
        void on_pieceReplaced(DataPiece *piece);
    
    private:
        QVector<DataModule*> modules; //separates Modules into Rectangles. Spacing modifiable.
        QVector<DataPiece*> graphs; //for every DataPiece, we will also have a QLineSeries and a QTimer.
        QVector<QLineSeries*> series;
        QVector<QTime*> timers;
    
    
    };
    

    Allowing me to import QLineSeries into my ListView of ChartViews here:

    //this will display our charts.
                        ListView {
                            objectName: "chartListView"
                            id: chartListView
                            x: 0
                            y: 130
                            width: 350
                            height: 350
    
                            anchors.top: controlRect.bottom
                            orientation: Qt.Vertical
    
                            /*
                                Procedure:
                                -load a DataPiece in to GraphModel. (name, units, value, maximum, minimum)
                                -Set up ChartView & LineSeries according to that DataPiece.
                             */
    
                            model: dataModel.getGraphsLength()
    
                            delegate: ChartView {
    
                                objectName: "chartView"
                                width: 350
                                height: 350
                                title: graphModel.getDataAt(index).getModuleName() + " " + graphModel.getDataAt(index).getName() + " vs. time"
                                property LineSeries imported_data
                                //data:
    
                                //need to import our data from dataModel. This is on the to-do list.
                            }
                        }
    

    -Is this a good approach? I am unsure if, in my context property class, if I should have a QVector of QCharts, or of QLineSeries.

    -In addition, I noticed in QML that ChartView has a property called "data", to which the ChartView documentation makes zero mention. Is this something I could use to import data to my delegate? If so, what type does "data" want? (LineSeries?)

    -Given that my axes will remain static for a given ChartView, I am thinking that these should be set up in my QML delegate. Is my thinking correct on this?

    Note: I should add that it is intended for the user to be able to add or remove graphs from the ListView of ChartViews.

    I apologize for the load of questions, I am just sort of in the dark as to how I should do this the proper way. The Qt documentation is lacking on this topic.

    Thanks in advance.

    Anything worthwhile is never achieved easily.

    1 Reply Last reply
    0
    • devDawgD Offline
      devDawgD Offline
      devDawg
      wrote on last edited by
      #2

      Still actively working to make this thing work. I would appreciate any comments on what I am trying to do, and if there is an easier or better way to do it.

      Thanks

      Anything worthwhile is never achieved easily.

      1 Reply Last reply
      0
      • devDawgD Offline
        devDawgD Offline
        devDawg
        wrote on last edited by
        #3

        Okay, so I have completely set up my data + signal handlers for new data in C++.

        My current problem is providing the correct format to the delegate of my ListView that will hold my dynamic set of ChartViews.

        Here is the .qml code:

        ListView {
                                objectName: "chartListView"
                                id: chartListView
                                x: 0
                                y: 130
                                width: 350
                                height: 350
        
                                anchors.top: controlRect.bottom
                                orientation: Qt.Vertical
        
                                /*
                                    Procedure:
                                    -load a DataPiece in to GraphModel. (name, units, value, maximum, minimum)
                                    -Set up ChartView & LineSeries according to that DataPiece.
                                 */
        
                                model: dataModel.getGraphsLength()
                                delegate: Component {
                                        ChartView { data: dataModel.getChartAt(index) }
        
                                } //data handling is done in C++.
        
                            }
        

        dataModel is a C++ class that I have registered as a context property.
        The error message I am getting from QML is : Error: Unknown method return type: QChart*. It points to where I am trying to set my ListView delegate.

        datamodel.h:

        class DataModel: public QObject
        {
        
            friend class QAbstractListModel;
        
            Q_OBJECT
        
        
        public:
            explicit DataModel(QObject * parent = nullptr);
            explicit DataModel(const QString file); //this is our main constructor here.
            explicit DataModel(DataModel&&); //move constructor
            explicit DataModel(const DataModel&); //copy constructor
        
            DataModel& operator=(const DataModel&);
            DataModel& operator=(DataModel&&);
        
            Q_INVOKABLE QString getTextBodyAt(int i);
            Q_INVOKABLE DataModule *getModuleAt(int i);
            Q_INVOKABLE int getModulesLength() { return modules.length(); }
            Q_INVOKABLE int getGraphsLength() { return graphs.length(); }
            Q_INVOKABLE DataPiece *getDataAt(int index) const;
            Q_INVOKABLE QChart* getChartAt(int index) const {return charts.at(index)->chart();}
            Q_INVOKABLE int getDataCount();
        
            //depending on the needed accuracy, we will have to look at which data type is needed. Probably won't end up being an int in all likelihood.
            Q_INVOKABLE int getCurrentTimeAt(int index);
        
            long timeToSeconds(QTime* time) const;
            void addModule(DataModule* mod_);
            void addDataGraph(DataPiece* piece);
            void replaceDataGraph(DataPiece* piece, int index); //replaces the graph at the given index with a new graph for the supplied DataPiece.
            void removeDataGraphAt(int i); //removes the graph at the given index.
            const QVector<DataModule*> getModel() const;  
            const QVector<DataPiece*> getGraphs() {return graphs;}
            const QVector<QTime*> getTimes() {return timers;}
        
            ~DataModel();
        signals:
            void pieceChanged(DataPiece*); //this signal might not be used anywhere.
            void pieceAdded(DataPiece*);
            void pieceReplaced(DataPiece*);
        
        public slots:
            void onClose();
            void on_pieceAdded(DataPiece *piece);
            void on_pieceReplaced(DataPiece *piece);
            void on_processError(QProcess::ProcessError error);
            void on_newValue(QString val);
        
        private:
            QVector<DataModule*> modules; //separates Modules into Rectangles. Spacing modifiable.
            QVector<DataPiece*> graphs; //for every DataPiece, we will also have a QLineSeries and a QTimer.
            QVector<QChartView*> charts;
            QVector<QTime*> timers;
        
        
        };
        

        So, should I be setting the delegate to be of type ChartView or Component? If I were to set it as a Component, how would I go about assigning its visual content to be my C++ ChartView at the index?

        Anything worthwhile is never achieved easily.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Hi,

          First thing: QObject based class are not copiable.

          QChart is a widget, so if you want to use it from QtQuick, you should take a look at KDAB's Declarative Widgets module

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          devDawgD 1 Reply Last reply
          2
          • SGaistS SGaist

            Hi,

            First thing: QObject based class are not copiable.

            QChart is a widget, so if you want to use it from QtQuick, you should take a look at KDAB's Declarative Widgets module

            devDawgD Offline
            devDawgD Offline
            devDawg
            wrote on last edited by
            #5

            @SGaist Sounds good. After wrestling with the QtCharts API since early this morning, I am kicking it to the curb and going with QCustomPlot. Seems to be a much cleaner, more efficient, and easier to use. I can't imagine I will have the same problems with QCustomPlot as I was with QtCharts.

            Nonetheless, I appreciate the response!

            Anything worthwhile is never achieved easily.

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              AFAIK, lots of people are satisfied with QCustomPlot.

              Depending on what you want/need, Qwt might also be of interest.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              1

              • Login

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