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. Subclasssed QSortFilterProxyModel to return concatenated fields
Forum Updated to NodeBB v4.3 + New Features

Subclasssed QSortFilterProxyModel to return concatenated fields

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 2 Posters 2.4k 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.
  • P Offline
    P Offline
    Panoss
    wrote on last edited by Panoss
    #1

    I have subclassed the QSortFilterProxyModel class and I want to combine two fields.
    It's source model gets data from a database table named 'clients' with fields 'firstname' and 'lastname'.
    Can these two fields be concatenated in one in my subclassed QSortFilterProxyModel?
    Something like concat( firstname , " " , lastname).

    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by
      #2

      Logic is wrong. Proxy models cannot map many-to-one.

      • How do you fill your source model?
      • Do you need changes made in the model to be filled back in the database?

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      1
      • P Offline
        P Offline
        Panoss
        wrote on last edited by Panoss
        #3

        Hi VRonin.
        Ifill my source model like this: model->setTable("clients"); (it 's a QSqlTableModel)

        I 'm just experimenting with QSortFilterProxyModel (and models in general) in order to become familiar (as newbee :) ).

        Look what I want to achieve:
        I have a db table.
        It's first row is empty.

        I want this table to 'feed' a QTableView and a QComboBox.

        In the table I want the first row (the empty) not to be shown.
        Also the table to be editable.
        I need changes made in the model of the table to be filled back in the database.
        And the combo 's model to be automatically updated.

        In the combo I want all the rows (and the first one) to be shown. But I also want the 2 fields concatenated.

        That's why I thought of using a proxy,
        because I 'feed' two widgets from one db table,
        I want the second model to be updated when the first changes,
        but their data, slightly, differ (by the first row).

        The first row in the db table is empty because I want the combo to have an option of 'nothing', no option, Null.
        But I don't want the table to have an empty row.
        So I thought of a model 'feeding' all the data to the combo, and a filter (this is why I thought of QSortFilterProxyModel) that removes the first row for the table.

        1 Reply Last reply
        0
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by VRonin
          #4

          the only "not morally wrong" way of doing what you are asking is using KExtraColumnsProxyModel from the KDE API (see here on how to build it), subclass it, call appendColumn() in the constructor and reimplement:

          virtual QVariant extraColumnData (const QModelIndex &parent, int row, int extraColumn, int role=Qt::DisplayRole) const override{
          if(role = Qt::DisplayRole)
          return sourceModel()->index(row,FirstNameColumn,parent).data(role).toString() + ", " + sourceModel()->index(row,LastNameColumn,parent).data(role).toString();
          return sourceModel()->index(row,FirstNameColumn,parent).data(role);
          }
          

          now you can set the combo model column to the extra column added

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          1
          • P Offline
            P Offline
            Panoss
            wrote on last edited by
            #5

            Ok, but what if I want to avoid the KDE (or any 'external'(non Qt) library)?

            1 Reply Last reply
            0
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by
              #6

              Diclaimer: This is EVIL and should not be done

              #include <QIdentityProxyModel>
              #include <QMultiHash>
              #include <QSet>
              template <class MergeType>
              class MergeDataProxy : public QIdentityProxyModel
              {
                  Q_DISABLE_COPY(MergeDataProxy)
              public:
                  explicit MergeDataProxy(QObject *parent=Q_NULLPTR)
                      :QIdentityProxyModel(parent)
                  {resetMergedRole();}
                  virtual ~MergeDataProxy(){}
                  void addMergedColumn(int copyFromCol, int copyToCol){
                      if(copyFromCol==copyToCol) return;
                      const QList<int> alreadyMerged=m_mergedColumns.values(copyToCol);
                      if(alreadyMerged.contains(copyFromCol))
                          return;
                      m_mergedColumns.insert(copyToCol,copyFromCol);
                  }
                  void clearMergedColumns(){m_mergedColumns.clear();}
                  const QHash<int, int>& mergedColumns() const{ return m_mergedColumns;}
                  const QSet<int>& mergedRoles() const{return m_mergedRoles;}
                  void setMergedRoles(const QSet<int> &mergedRoles){m_mergedRoles=mergedRoles;}
                  void addMergedRole(int role){m_mergedRoles.insert(role);}
                  void removeMergedRole(int role){m_mergedRoles.remove(role);}
                  void clearMergedRole(){m_mergedRoles.clear();}
                  void resetMergedRole(){clearMergedRole(); m_mergedRoles << Qt::DisplayRole;}
                  const MergeType& separator() const{return m_separator;}
                  void setSeparator(const MergeType &separator){m_separator=separator;}
                  virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE{
                      Q_ASSERT(index.model()==this);
                      const QVariant baseData= QIdentityProxyModel::data(index,role);
                      if(!m_mergedRoles.contains(role))
                          return baseData;
                      const QList<int> findCol = m_mergedColumns.values(index.column());
                      if(findCol.isEmpty())
                          return baseData;
                      MergeType result  = baseData.value<MergeType>();
                      foreach(int singleCol,findCol){
                          result += m_separator;
                          result += QIdentityProxyModel::data(QIdentityProxyModel::index(index.row(),singleCol,index.parent()),role).value<MergeType>();
                      }
                      return result;
                  }
              private:
                  QMultiHash<int,int> m_mergedColumns;
                  QSet<int> m_mergedRoles;
                  MergeType m_separator;
              };
              

              now you can use something like:

              MergeDataProxy<QString>* mergProx=new MergeDataProxy<QString>(this);
                    mergProx->setSourceModel(model);
                    mergProx->addMergedColumn(LastNameColumn,FirstNameColumn);
                    mergProx->setSeparator(", ");
              

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              1 Reply Last reply
              0
              • P Offline
                P Offline
                Panoss
                wrote on last edited by Panoss
                #7

                This disclaimer of yours really scared the hell out of me! :)
                So, what you 're really saying, is that KExtraColumnsProxyModel is the only way?

                1 Reply Last reply
                0
                • VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by
                  #8

                  For what you want to do (use it in a combobox) my proxy is good but for anyone googling this in the future they must know there is no easy way of doing one-to-many or many-to-one proxy model.

                  For example, in my proxy, calling addMergedRole(Qt::EditRole); and trying to edit the cell will turn your base model in a steaming pile of 💩 pretty fast

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  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