Results 1 to 9 of 9

Thread: Add virtual rows & columns to a proxy model

  1. #1
    Join Date
    Jul 2015
    Posts
    7
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Add virtual rows & columns to a proxy model

    Hi,

    i have a QSortFilterProxyModel and i'd like to add some rows and columns, but only in the proxy model.

    For example, i have 6 rows and 4 columns and i want to add an additional column with data not from the source model.

    I've already reimplemented rowCount, columnCount and data. The QTableView shows the correct count of rows and columns but there is not data in the "virtual" column. I found out, that the QModelIndex rage in data() is only from column 0 to 3, but never comes to column 4.

    What else do i have to do, to get the additional column(s)?

    Thank you.

    Regards,
    Mani

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,366
    Thanks
    36
    Thanked 1,535 Times in 1,486 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Add virtual rows & columns to a proxy model

    So columnCount() of the proxy returns 5 but the proxy's data() never gets called with index.column==4?

    Cheers,
    _

  3. #3
    Join Date
    Jul 2015
    Posts
    7
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Add virtual rows & columns to a proxy model

    Yes, this is the problem! The whole problem in one sentence ...

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,366
    Thanks
    36
    Thanked 1,535 Times in 1,486 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Add virtual rows & columns to a proxy model

    Ok, this is strange, the view should be trying to get data for those cells.

    Can you post the code of your proxy model or maybe even a minimal example demonstrating the problem?

    Cheers,
    _

  5. #5
    Join Date
    Jul 2015
    Posts
    7
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Add virtual rows & columns to a proxy model

    This demo model shows the problem. It starts with 6 rows and 4 columns and in the proxy model i remove 3 rows and add one column. The last column is created but there is no data in it, it's also not clickable.

    Qt Code:
    1. #ifndef TestTableModel_H
    2. #define TestTableModel_H
    3.  
    4. #include <QAbstractTableModel>
    5.  
    6. class TestTableModel : public QAbstractTableModel
    7. {
    8. private:
    9. typedef QVector<QVariant> RowData;
    10. typedef QVector<RowData> ModelData;
    11.  
    12. public:
    13. TestTableModel(QObject *parent = 0);
    14.  
    15. int rowCount(const QModelIndex &parent) const;
    16. int columnCount(const QModelIndex &parent) const;
    17. QVariant data(const QModelIndex &index, int role) const;
    18. QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    19.  
    20. private:
    21. void init();
    22.  
    23. private:
    24. ModelData mModelData;
    25. };
    26.  
    27. #endif // TestTableModel_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "TestTableModel.h"
    2.  
    3. TestTableModel::TestTableModel(QObject *parent) : QAbstractTableModel(parent)
    4. {
    5. init();
    6. }
    7.  
    8. int TestTableModel::rowCount(const QModelIndex &parent) const
    9. {
    10. if(parent.isValid())
    11. return 0;
    12. else
    13. return mModelData.size();
    14. }
    15.  
    16. int TestTableModel::columnCount(const QModelIndex &parent) const
    17. {
    18. if(parent.isValid())
    19. return 0;
    20. else
    21. {
    22. if(mModelData.size() > 0)
    23. return mModelData.at(0).size();
    24. }
    25.  
    26. return 0;
    27. }
    28.  
    29. QVariant TestTableModel::data(const QModelIndex &index, int role) const
    30. {
    31. if(role == Qt::DisplayRole)
    32. {
    33. if(index.isValid())
    34. {
    35. return mModelData.at(index.row()).at(index.column());
    36. }
    37. }
    38.  
    39. return QVariant();
    40. }
    41.  
    42. QVariant TestTableModel::headerData(int section, Qt::Orientation orientation, int role) const
    43. {
    44. if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
    45. {
    46. switch(section)
    47. {
    48. case 0:
    49. return "Value1";
    50. case 1:
    51. return "Value2";
    52. case 2:
    53. return "Value3";
    54. case 3:
    55. return "Value4";
    56. default:
    57. return QVariant();
    58. }
    59. }
    60.  
    61. return QVariant();
    62. }
    63.  
    64. void TestTableModel::init()
    65. {
    66. RowData rdA;
    67. rdA.append("A");
    68. rdA.append(1000);
    69. rdA.append(800);
    70. rdA.append(100);
    71.  
    72. mModelData.append(rdA);
    73.  
    74. RowData rdB;
    75. rdB.append("B");
    76. rdB.append(2500);
    77. rdB.append(2000);
    78. rdB.append(300);
    79.  
    80. mModelData.append(rdB);
    81.  
    82. RowData rdC;
    83. rdC.append("C");
    84. rdC.append(1400);
    85. rdC.append(1120);
    86. rdC.append(100);
    87.  
    88. mModelData.append(rdC);
    89.  
    90. RowData rdA1;
    91. rdA1.append("A");
    92. rdA1.append(1200);
    93. rdA1.append(960);
    94. rdA1.append(180);
    95.  
    96. mModelData.append(rdA1);
    97.  
    98. RowData rdA2;
    99. rdA2.append("A");
    100. rdA2.append(1000);
    101. rdA2.append(800);
    102. rdA2.append(100);
    103.  
    104. mModelData.append(rdA2);
    105.  
    106. RowData rdB1;
    107. rdB1.append("B");
    108. rdB1.append(1500);
    109. rdB1.append(1200);
    110. rdB1.append(100);
    111.  
    112. mModelData.append(rdB1);
    113. }
    To copy to clipboard, switch view to plain text mode 

    And the proxy model
    Qt Code:
    1. #ifndef TestTableProxyModel_H
    2. #define TestTableProxyModel_H
    3.  
    4. #include <QSortFilterProxyModel>
    5.  
    6. class TestTableProxyModel : public QSortFilterProxyModel
    7. {
    8. private:
    9. typedef QVector<QVariant> RowData;
    10. typedef QVector<RowData> ModelData;
    11.  
    12. public:
    13. TestTableProxyModel(QObject *parent = 0);
    14. int rowCount(const QModelIndex &parent) const;
    15. int columnCount(const QModelIndex &parent) const;
    16. QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    17. QVariant data(const QModelIndex &index, int role) const;
    18.  
    19. void refreshView();
    20.  
    21. private:
    22. QStringList mHeaderFields;
    23. int mRowCount;
    24. int mColumnCount;
    25. ModelData mTmpModelData;
    26. bool mUpdateDone;
    27. };
    28.  
    29. #endif // TestTableProxyModel_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "TestTableProxyModel.h"
    2.  
    3. TestTableProxyModel::TestTableProxyModel(QObject *parent)
    4. : QSortFilterProxyModel(parent), mRowCount(0), mColumnCount(0), mUpdateDone(true)
    5. {
    6.  
    7. }
    8.  
    9. int TestTableProxyModel::rowCount(const QModelIndex &parent) const
    10. {
    11. if(parent.isValid())
    12. return 0;
    13.  
    14. if(mRowCount > 0 && mUpdateDone)
    15. return mRowCount;
    16. else
    17. return QSortFilterProxyModel::rowCount(parent);
    18. }
    19.  
    20. int TestTableProxyModel::columnCount(const QModelIndex &parent) const
    21. {
    22. if(parent.isValid())
    23. return 0;
    24.  
    25. if(mColumnCount > 0 && mUpdateDone)
    26. return mColumnCount;
    27. else
    28. return QSortFilterProxyModel::columnCount(parent);
    29. }
    30.  
    31. QVariant TestTableProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
    32. {
    33. if(mUpdateDone)
    34. {
    35. if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
    36. {
    37. if(!mHeaderFields.isEmpty())
    38. {
    39. if(section < mHeaderFields.size())
    40. return mHeaderFields.at(section);
    41. else
    42. return QVariant();
    43. }
    44. }
    45. }
    46.  
    47. return QSortFilterProxyModel::headerData(section, orientation, role);
    48. }
    49.  
    50. QVariant TestTableProxyModel::data(const QModelIndex &index, int role) const
    51. {
    52. if(mUpdateDone)
    53. {
    54. if(role == Qt::DisplayRole)
    55. {
    56. if(!mTmpModelData.isEmpty())
    57. {
    58. if(index.row() < mTmpModelData.size())
    59. {
    60. if(index.column() < mTmpModelData.at(index.row()).size())
    61. return mTmpModelData.at(index.row()).at(index.column());
    62. }
    63. else
    64. return QVariant();
    65. }
    66. }
    67. }
    68.  
    69. return QSortFilterProxyModel::data(index, role);
    70. }
    71.  
    72. void TestTableProxyModel::refreshView()
    73. {
    74. mUpdateDone = false;
    75.  
    76. mRowCount = 3;
    77. mColumnCount = 5;
    78.  
    79. for(int i=0;i<mColumnCount;i++)
    80. mHeaderFields.append(QString("Column").append(QString::number(i+1)));
    81.  
    82. for(int i=0;i<mRowCount;i++)
    83. {
    84. RowData rd;
    85. for(int j=0;j<mColumnCount;j++)
    86. rd.append(QString("Value").append(QString::number(i+1)).append("_").append(QString::number(j+1)));
    87.  
    88. mTmpModelData.append(rd);
    89. }
    90.  
    91. mUpdateDone = true;
    92.  
    93. invalidate();
    94. }
    To copy to clipboard, switch view to plain text mode 

  6. #6
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,016
    Thanks
    233
    Thanked 638 Times in 628 Posts
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: Add virtual rows & columns to a proxy model

    So where is this magical "refreshView()" method being called?

    Your base model isn't calling any of the methods it should be when changing the model - things like beginInsertRows(), endInsertRows(), or even modelReset(). These things are necessary for the model to properly notify listeners (views, proxies, etc.) that something has changed and they need to update themselves. You shouldn't need to implement magic methods to get your proxy updated or to have to transfer data from your base model into the proxy.

    In order to get clickable behaviour for your virtual column, you will need to implement the flags() method for your proxy.

  7. #7
    Join Date
    Jul 2015
    Posts
    7
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Add virtual rows & columns to a proxy model

    Thank you for your reply.

    The model itself should not be changed, i only want to add a "virtual" column with the proxy model to the view. refreshView() is called from a button on a form next to the table view. I also don't want to transfer any data from the base model to the proxy.

    I have also reimplemented the flags() method but it does not change anything, same behaviour as before.

  8. #8
    Join Date
    Jul 2015
    Posts
    7
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Add virtual rows & columns to a proxy model

    I found the solution here.

    I had to add the following methods to my proxy class:
    Qt Code:
    1. QModelIndex index(int row, int column, const QModelIndex& parent=QModelIndex()) const {
    2. return createIndex(row,column,row);
    3. }
    4.  
    5. QModelIndex parent(const QModelIndex &index) const {
    6. //Works only for non-tree models
    7. return QModelIndex();
    8. }
    9.  
    10. QModelIndex mapFromSource(const QModelIndex &source) const {
    11. return index(source.row(), source.column(), source.parent());
    12. }
    13.  
    14. QModelIndex mapToSource(const QModelIndex &proxy) const {
    15. return (sourceModel()&&proxy.isValid())
    16. ? sourceModel()->index(proxy.row(), proxy.column(), proxy.parent())
    17. }
    To copy to clipboard, switch view to plain text mode 

  9. The following user says thank you to STM for this useful post:

    d_stranz (20th December 2018)

  10. #9
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,016
    Thanks
    233
    Thanked 638 Times in 628 Posts
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: Add virtual rows & columns to a proxy model

    And here I thought elephants never forget. I guess that doesn't apply to old elephants.

    Just got bit by this exact same issue this week, and finally decided to ask Google. That led me here, and adding the index() and parent() methods fixed it. (I had already added the map...() methods).

    In my case, my proxy added a column which was mapped to one of the source model columns, but it split one of the source columns into two, each of which modified the original data - that is, if the original columns were x and y, it mapped x into x' and y', and y into z' by applying two different arithmetic transformations to the original x.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

Similar Threads

  1. Replies: 24
    Last Post: 18th September 2013, 06:35
  2. Replies: 1
    Last Post: 29th August 2013, 05:41
  3. Adding more than one virtual column in proxy model
    By qavaxb in forum Qt Programming
    Replies: 5
    Last Post: 26th January 2013, 16:09
  4. Source Model Ad Proxy Model
    By sajis997 in forum Qt Programming
    Replies: 1
    Last Post: 19th July 2011, 05:13
  5. Custom Model and Proxy Model
    By frank100 in forum Qt Programming
    Replies: 1
    Last Post: 20th December 2010, 14:30

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.