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. Using different Views with one model and different data
Forum Updated to NodeBB v4.3 + New Features

Using different Views with one model and different data

Scheduled Pinned Locked Moved Unsolved General and Desktop
22 Posts 3 Posters 4.5k Views 1 Watching
  • 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.
  • W Offline
    W Offline
    Wuzi
    wrote on last edited by
    #5

    ok I set the wrong prefix, but my idea will not work
    Main.cpp:

        SignalNamesProxyModel* proxy_signal_names = new SignalNamesProxyModel(this);
        proxy_signal_names->setSourceModel(m_data.getSignalNames());
        m_listview_signal->setModel(proxy_signal_names);es());
    

    My plan was to set the row to a negative number, so I know in the model, that this will get different data:

    Proxymodel.cpp:

    QVariant SignalNamesProxyModel::data(const QModelIndex &index, int role) const {
    
        const QAbstractItemModel * model = index.model();
        QString value = sourceModel()->data(model->index(-1,index.row()),role).toString();
        return value;
    }
    

    Model.cpp:

    QVariant SignalData::data(const QModelIndex &index, int role) const {
    
        int row = index.row();
        int column = index.column();
    
    
        if (role == Qt::DisplayRole){
            if(row >= 0){
                return m_data[row][column];
            }else if(row == -1){
                return m_column_names[column];
            }else if(row == -2){
                return m_column_units[column];
            }
        }
    
        return QVariant();
    }
    

    But this does not work, because when I set the row to a negative number, the column becomes -1 too.

    Is there another way to get different data?

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

      Hi,

      Wouldn't the KConcatenateRowsProxyModel do what you want ?

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

      W 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi,

        Wouldn't the KConcatenateRowsProxyModel do what you want ?

        W Offline
        W Offline
        Wuzi
        wrote on last edited by Wuzi
        #7

        @SGaist said in Using different Views with one model and different data:

        Wouldn't the KConcatenateRowsProxyModel do what you want ?

        Thank you SGaist, but in the documentation there is written, that it is assumed that all rows have the same number ("All models are assumed to have the same number of columns")

        This is my dataclass:

        class SignalData : public QAbstractTableModel
        {
            Q_OBJECT
        public:
            SignalData(Data *parent);
            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;
            bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()); // wieso darf hier kein override stehen?
            bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
            int readMDFFile(QString path);
        private:
            Data* m_parent;
        
            std::vector<std::vector<double> > m_data;
            std::vector<QString> m_column_names;
            std::vector<QString> m_column_units;
        };
        

        m_data are the datas, column_names are the names of the data columns and olumn_units are the units of the data columns.
        For example: size(m_column_names) = size(m_column_units) = 8
        and size(m_data) = 8x1000 or so

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

          Right, I was thinking about KExtraColumnsProxyModel.

          But I realise I might have misunderstood your final goal.

          Can you show an image of what you would like to show in your view ?

          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
          0
          • W Offline
            W Offline
            Wuzi
            wrote on last edited by
            #9

            Sorry for my bad explanation.

            Here is the main view.

            0_1540573885327_MDFViewer.png

            This application should load Data files *.mf4 and store this data. The signals which are in this file are listen in the Listview "Signals". If you click on one of this signals, you will see a preview of this signal in the "Preview" Listview. The central Widget contains a tabwidget, where you can add charts. At the end you should be able to drag a Signal name in one of this charts, and the signal will be showed in this chart.

            So I need the Signal name in the "Signals" Listview and the Signal data in the "Preview" and in the central widget charts.

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

              Ok, then isn't it rather a tree style model that you should have ?

              Or if still a table style, you should maybe consider creating an object that encapsulates your signals data and build your model on top of that.

              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
              • W Offline
                W Offline
                Wuzi
                wrote on last edited by
                #11

                @SGaist said in Using different Views with one model and different data:

                Ok, then isn't it rather a tree style model that you should have ?

                You mean something like this:
                0_1540627115290_TreeView.png
                Sounds good for me, thanks

                @SGaist said in Using different Views with one model and different data:

                Or if still a table style, you should maybe consider creating an object that encapsulates your signals data and build your model on top of that

                You mean. creating for every signal a own model? Putting The signal names in a seperate model than the data?

                1 Reply Last reply
                0
                • W Offline
                  W Offline
                  Wuzi
                  wrote on last edited by
                  #12

                  No I created a tree model like in this example.

                  This is the code which add the data as SignalDataTreeItems to the m_root_item

                      beginInsertRows(QModelIndex(), 0, channel_list.size()-1);
                  
                      for (int channel_index : channel_list) {
                          const mdf::channel& ch = channels[channel_index];
                  
                          QList<QVariant> signalname = {QVariant::fromValue<QString>(QString::fromStdString(ch.get_name()))};
                          SignalDataTreeItem *signal = new SignalDataTreeItem(signalname);
                  
                          QList<QVariant> unit_string = {QVariant::fromValue<QString>(QString::fromStdString(ch.get_metadata_unit()))};
                          SignalDataTreeItem *unit = new SignalDataTreeItem(unit_string,signal);
                          signal->appendChild(unit);
                  
                  
                          // TODO: optimize this step!
                          std::vector<double> column;
                          ch.get_data_real(column);
                          QList<QVariant> datas;
                          foreach(double d, column){
                              datas.append(QVariant(d));
                          }
                          SignalDataTreeItem *data = new SignalDataTreeItem(datas,signal);
                          signal->appendChild(data);
                  
                          m_rootItem->appendChild(signal);
                      }
                  
                      endInsertRows();
                  

                  The problem is, that in the proxy the function data will never called.

                  SignalNamesProxyModel::SignalNamesProxyModel(QObject *parent): QSortFilterProxyModel (parent){
                  }
                  
                  int SignalNamesProxyModel::rowCount(const QModelIndex &parent) const {
                      int rowcount = sourceModel()->rowCount(QModelIndex()); // of root item (number of signals)
                      return rowcount;
                  }
                  
                  int SignalNamesProxyModel::columnCount(const QModelIndex &parent) const{
                      return 1;
                  }
                  
                  QVariant SignalNamesProxyModel::data(const QModelIndex &index, int role) const {
                  
                      QString value = sourceModel()->data(index).toString();
                  
                      return value;
                  }
                  
                  QModelIndex SignalNamesProxyModel::index(int row, int column, const QModelIndex &parent)const {
                  
                      return sourceModel()->index(row,0,QModelIndex()); // child "row" of m_root_item of sourceModel (signal)
                  }
                  

                  The problem is, that I don't understand how do I have to use beginInsertRows and endInsertRows, when I have to different datas, because the row count matches only for one view not for both at the same time.

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

                    I just re-read your first post. In the end, can't it be simplified to a two column table ?

                    First column: name
                    Second column: data

                    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
                    0
                    • W Offline
                      W Offline
                      Wuzi
                      wrote on last edited by
                      #14

                      @SGaist said in Using different Views with one model and different data:

                      I just re-read your first post. In the end, can't it be simplified to a two column table ?
                      First column: name
                      Second column: data

                      The problem is, that in the data variable are multiple signals:

                      row0, column0: signal0, first value
                      row0, column1: signal0, second value
                      row1, column0: signal1, first value
                      row1, colimn1: signal1, second value
                      ....

                      So this is the second concept I tested while the weekend, it has nothing to do with the tree model.
                      I moved the signal name in a seperate listmodel (So it is easy to list all signal names in a list view).
                      The data I store in a table model.

                      The problem is, how can I set, which row of this table should be shown?
                      For example:
                      I have a chart where I would like to plot some of this data (but only few signals, not every row). I would like to select which signal should be used for the x axis and which should be used on the y axis. To do that I created a QSortFilterProxyModel and reimplemented the rowCount, columnCount and the mapToSource function as follows:

                      int SignalPreviewProxyModel::rowCount(const QModelIndex &parent) const {
                          return 2*m_mapToSourceIndex.lenght();
                      }
                      
                      int SignalPreviewProxyModel::columnCount(const QModelIndex &parent) const{
                      
                          int column = sourceModel()->columnCount(parent);
                          return column;
                      }
                      
                      QModelIndex SignalPreviewProxyModel::mapToSource(const QModelIndex & proxyIndex) const {
                      
                          if(!proxyIndex.isValid()){
                              return QModelIndex();
                          }
                      
                          int row = proxyIndex.row();
                          int column = proxyIndex.column();
                      
                          int axis = row % 2; // modulo 2, because x and y axis
                          int value = row /2; // graph
                      
                          if(axis == 0){
                              row = m_mapToSourceIndex.at(value).first;
                          }else{
                              row = m_mapToSourceIndex.at(value).second;
                          }
                          QModelIndex index2 = sourceModel()->index(row,column,QModelIndex()); // get from already existing item the index
                          return index2;
                      }
                      

                      In this concept, the problem is, that mapToSource transformation is not invertable ( when there should be the possibility to display mutiple signals in the graph, this is why m_mapToSourceIndex is a vector of mappings), so I'm not able create the mapFromSource function and I get a segmentation fault.

                      I really don't know how I can solve this problem (which is the most common way?).
                      Thanks for helping me! :)

                      0_1540820607321_MDFViewer.png

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

                        I'm still wondering if there's not a bit of model over-engineering.

                        Wouldn't it be simpler to have a class that encapsulates a "signal". Store of all your signals in a QVector of that class.

                        Then build a simple table module that would return the data from the correct signal object.

                        struct Signal
                        {
                            QString name;
                            QString unit;
                            QVector<QVariant> data;
                        };
                        
                        class SignalTableModel
                        {
                        
                        QVariant data(const QModelIndex &index, int role) const
                        {
                            // Add index validity checks
                            Signal signal(_signalVector.at(index.row()));
                            if (index.column() == 1) {
                                return signal.name();
                            }
                           // etc.
                        }
                        
                        };
                        

                        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
                        0
                        • W Offline
                          W Offline
                          Wuzi
                          wrote on last edited by
                          #16

                          So you mean, when column ==1 then return name, when column == 2 then return unit and when the column is greater than 2 return the respective value?

                          So then I have to use a proxy between this model and the signal name list view and set the columcount to 1?

                          And for the chartview(derived from tableview) I have to use a proxy, which maps the index to +2 because the first two rows are name and unit?

                          Do I understand you correct?

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

                            What do you mean by respective value ?

                            You can use a QListView so no need for fiddling with a proxy model.

                            And for the table view, you can simply hide the columns you don't want to show.

                            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
                            • W Offline
                              W Offline
                              Wuzi
                              wrote on last edited by
                              #18

                              @SGaist said in Using different Views with one model and different data:

                              What do you mean by respective value ?
                              One signal consists of multiple data (due to a time range on which the signal was logged). The different signals are stored in a 2d array:

                              std::vector<std::vector<double> > m_data;
                              

                              @SGaist said in Using different Views with one model and different data:

                              You can use a QListView so no need for fiddling with a proxy model.

                              Yes for the signal names I have a QListView. The signal names are stored in a list model. This works fine.

                              Or did I missunderstand your question?

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

                                You wrote that you wanted to use a proxy and setting the columns count to 1 so I thought you were trying to "re-invent" QListView.

                                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
                                0
                                • W Offline
                                  W Offline
                                  Wuzi
                                  wrote on last edited by
                                  #20

                                  @SGaist said in Using different Views with one model and different data:

                                  You wrote that you wanted to use a proxy and setting the columns count to 1 so I thought you were trying to "re-invent" QListView.

                                  Oh sorry. this was in the concept with the tree model, but in the actual concept I have the data stored in a tablemodel.

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

                                    Ok, good.

                                    So at what point are you now ?

                                    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
                                    0
                                    • W Offline
                                      W Offline
                                      Wuzi
                                      wrote on last edited by
                                      #22

                                      @SGaist said in Using different Views with one model and different data:

                                      Ok, good.
                                      So at what point are you now ?

                                      After reading you question I had a new idea (before I thought it is not possible to use KDChart to plot) :D :

                                      1. a data class which stores all the data
                                      2. a table model which stores a pointer to the data which I would like to display.
                                        In this model I reimplement the data, rowcount and columncount function as following:
                                      class Data
                                      {
                                      public:
                                         QVector<double>* getDataPointer(int index){return &m_data.at(index);}
                                      private:
                                       QVector<QVector<double>> m_data;
                                      };
                                      
                                      // Every Diagram uses an object of this class
                                      class SignalModel: public QAbstractTableModel
                                      {
                                      public:
                                      - override rowcount
                                      - override columncount
                                      - override data
                                      void addData(QVector<double>* xaxis, QVector<double>* yaxis);
                                      private:
                                          QVector<QVector<double>*> m_data;
                                      };
                                      
                                      void SignalModel::addData(QVector<double>* xaxis, QVector<double>* yaxis){
                                      // KDChart expects, that the axis keys and values are stored in different rows
                                      m_data.append(xaxis);
                                      m_data.append(yaxis);
                                      }
                                      
                                      int SignalModel::rowCount(const QModelIndex &parent) const {
                                        return m_data.lenght();
                                      }
                                      
                                      int SignalModel::columnCount(const QModelIndex &parent) const{
                                      
                                        int column = m_data.at(0)->length()
                                        return column;
                                      }
                                      
                                      QVariant SignalModel::data(const QModelIndex &index) const{
                                      
                                        return m_data.at(index.row)->at(index.column);
                                      }
                                      
                                      

                                      removeRow and insertRow must be reimplemented too, to add dynamically new data.

                                      For showing the signal names I would reimplement a listmodel.

                                      I think it is the simplest method to do my task. (If there are errors in my code, it is because I didn't tested it, it's just a sketch).
                                      I found kst-plot which does exactly what I want. So I think it is easier to extend this program and help to contribute to this one, than rewriting a new one.

                                      Thank you SGaist for your help and the inspiration. If this last concept is unclear, just write and I will extend it.

                                      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