Results 1 to 19 of 19

Thread: 2 subclasses of QSortFilterProxyModel behind each other.

  1. #1
    Join Date
    Apr 2013
    Posts
    27
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default 2 subclasses of QSortFilterProxyModel behind each other.

    Hi,

    currently I am using 2 subclasses of QSortFilterProxyModel

    Some of the data needs to be editable, some data not. So i made a QSortFilterProxyModelDisableEdit that does only remove the editable flag from a column.
    On some tables I need an extra column that is not in the database. There for i used a ProxyModel described in this threat.

    The objects are connected in the following way:
    Qt Code:
    1. QSqlTableModel* DataTable = new QSqlTableModel();
    2.  
    3. SqlProxyModelAddColumn* AddColumn = new SqlProxyModelAddColumn();
    4. AddColumn->setSourceModel(DataTable);
    5.  
    6. SqlProxyModelDisalbeEdit* DisableEdit = new SqlProxyModelDisalbeEdit();
    7. DisableEdit->setSourceModel(AddColumn);
    To copy to clipboard, switch view to plain text mode 


    Noting is set in DisableEdit so it acts like a QSqlProxyModel,
    AddColumn implementation is descriped in ProxyModel

    When i try to edit some value for the DataTable all works fine.
    but when i try to edit a value for the added column set data is never called. So i think there is something going wrong with the indexes, but i cant find the problem.

    Any help is appreciated, thanks.

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,368
    Thanks
    3
    Thanked 5,018 Times in 4,794 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Why don't you subclass QIdentityProxyModel instead?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. The following user says thank you to wysota for this useful post:

    Delphi (29th May 2013)

  4. #3
    Join Date
    Apr 2013
    Posts
    27
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    I needed to sort something as well on that place,

    I found the root of the problem: ProxyModel.

    ProxyModel with a QsqlQueryModel as source works.
    When using a QSqlTablemodel or a other ProxyModel it stops working.

    has someome a neat solution for the index problem from ProxyModel

  5. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,368
    Thanks
    3
    Thanked 5,018 Times in 4,794 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Don't do 10 tasks at once. Have one proxy for modifying item flags, another for adding/removing columns and one more for sorting. Assemble them all to get the final solution.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  6. #5
    Join Date
    Apr 2013
    Posts
    27
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    I we do not quite understand each other,
    that's what I try to do exactly.

    a model that changes flags and can filter
    and a model that adds a column.


    the problem lies with the ProxyModel

    when it is having a QsqlQueryModel as source model it works correctly.
    when it is having a QsqlTableModel or ProxyModel as sourceModel it is displaying correct but setdata never gets called.
    the flags are working correctly.

    So i think it is caused by the Indexes. As previous post said.
    Is there someone that can help me get a neat solution for the index problem in ProxyModel

    Any help is appreciated, thanks.

  7. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,368
    Thanks
    3
    Thanked 5,018 Times in 4,794 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Quote Originally Posted by Delphi View Post
    the problem lies with the ProxyModel
    Get rid of that model and use a subclass of QIdentityProxyModel as advised. There you don't need to reimplement mapFromSource() and mapToSource() which are the source of your trouble.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  8. #7
    Join Date
    Apr 2013
    Posts
    27
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Why would be a QIdentityProxyModel easier?

    I still will have problems with an index.
    because (set)data works with them. Which index will have the extra column? It still needs to be maped by maped to and from source.

    I also think that ToSource and FromSource need to be reimplemented, because QIdentityProxyModel works with 1 source model. My subclass needs to work with 1 source model and an extra column.

  9. #8
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Ok, I looked at the ProxyModel in the other post, it looks fine and will works for all QStandardItemModel, QSqlTableModel and QSqlQueryModel (only first column is editable, and other columns are redable)

    Here is an example using the similar ProxyModel (with few changes), and it shows all combinations simultaneously.
    ProxyModel_All.jpg
    Qt Code:
    1. #include <QtGui>
    2. #include <QtSql>
    3. #include <QtWidgets>
    4. #include <QApplication>
    5.  
    6. // Add one extra column at the begining
    7. class ProxyModel : public QAbstractProxyModel
    8. {
    9. Q_OBJECT
    10. public:
    11. explicit ProxyModel(QObject * parent = 0)
    12. , mData()
    13. {
    14. connect(this, SIGNAL(sourceModelChanged()), SLOT(slotSourceModelChanged()));
    15. }
    16.  
    17. protected slots:
    18. void slotSourceModelChanged(void)
    19. {
    20. disconnect(this, SLOT(slotDataChanged(QModelIndex,QModelIndex)));
    21. connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(slotDataChanged(QModelIndex,QModelIndex)));
    22. }
    23.  
    24. void slotDataChanged(const QModelIndex first, QModelIndex last)
    25. {
    26. emit dataChanged(mapFromSource(first), mapFromSource(last));
    27. }
    28.  
    29. QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const
    30. {
    31. if(!parent.isValid())
    32. return createIndex(row, column);
    33. return QModelIndex();
    34. }
    35.  
    36. QModelIndex parent(const QModelIndex & /*child*/) const
    37. {
    38. return QModelIndex();
    39. }
    40.  
    41. int rowCount(const QModelIndex & parent = QModelIndex()) const
    42. {
    43. if(!parent.isValid())
    44. return sourceModel()->rowCount(QModelIndex());
    45. return 0;
    46. }
    47.  
    48. int columnCount(const QModelIndex & parent = QModelIndex()) const
    49. {
    50. if(!parent.isValid())
    51. return sourceModel()->columnCount() + 1;
    52. return 0;
    53. }
    54.  
    55. QModelIndex mapToSource(const QModelIndex & proxyIndex) const
    56. {
    57. if(!proxyIndex.isValid())
    58. return QModelIndex();
    59.  
    60. if(proxyIndex.column() == 0)
    61. return createIndex(proxyIndex.row(), -1, (quintptr)-1); //<<<<<<<<<<<<<<<<<<<<<< This is a workaround. Note it is weird to create a index of proxy model and return as if it were an index of sourceModel(), it is not a common way but will work (at-least in this case)
    62.  
    63. return sourceModel()->index(proxyIndex.row(), proxyIndex.column() - 1);
    64. }
    65.  
    66. QModelIndex mapFromSource(const QModelIndex & sourceIndex) const
    67. {
    68. if(!sourceIndex.isValid())
    69. {
    70. if((sourceIndex.row() > -1) and //<<<<<<<<<<<<<<<<<<<<<< This is a workaround.
    71. (sourceIndex.column() == -1) and
    72. (sourceIndex.internalId() == (quintptr)-1) )
    73. return index(sourceIndex.row(), 0);
    74. else
    75. return QModelIndex();
    76. }
    77.  
    78. return index(sourceIndex.row(), sourceIndex.column() + 1);
    79. }
    80.  
    81. QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const
    82. {
    83. if(orientation == Qt::Horizontal)
    84. {
    85. if(section == 0)
    86. return QString("Proxy Column");
    87. return sourceModel()->headerData(section - 1, orientation, role);
    88. }
    89. return sourceModel()->headerData(section, orientation, role);
    90. }
    91.  
    92. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
    93. {
    94. if(index.column() == 0)
    95. {
    96. if((role == Qt::DisplayRole) or (role == Qt::EditRole))
    97. if(index.row() < mData.size())
    98. return mData.at(index.row());
    99. return QVariant();
    100. }
    101.  
    102. return sourceModel()->data(mapToSource(index), role);
    103. }
    104.  
    105. bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole)
    106. {
    107. if(index.column() == 0)
    108. {
    109. if((role == Qt::DisplayRole) or (role == Qt::EditRole))
    110. {
    111. while((index.row() + 1) > mData.size())
    112. mData.append(QString());
    113. mData[index.row()] = value.toString();
    114. emit dataChanged(index, index);
    115. return true;
    116. }
    117. return false;
    118. }
    119.  
    120. return sourceModel()->setData(mapToSource(index), value, role);
    121. }
    122.  
    123. Qt::ItemFlags flags(const QModelIndex & index) const
    124. {
    125. if(index.column() == 0)
    126. return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
    127.  
    128. return sourceModel()->flags(mapToSource(index));
    129. }
    130.  
    131. private:
    132. QStringList mData;
    133. };
    134.  
    135. class Widget : public QWidget
    136. {
    137. public:
    138. explicit Widget(QWidget * parent = 0)
    139. : QWidget(parent)
    140. , mGridLayout(new QGridLayout(this))
    141. { }
    142.  
    143. void addWidget(int row, int col, QWidget * widget, const QString & title)
    144. {
    145. mGridLayout->addWidget(new QLabel(title), row * 2, col, 1, 1, Qt::AlignCenter);
    146. mGridLayout->addWidget(widget, (row * 2) + 1, col, 1, 1);
    147. }
    148.  
    149. private:
    150. QGridLayout * mGridLayout;
    151. };
    152.  
    153. const QString TableName = "Locations";
    154. const QString Column1 = "Country";
    155. const QString Column2 = "Location";
    156. const QStringList countries = QStringList() << "Norway" << "Australia" << "USA" << "China" << "Germany";
    157. const QStringList locations = QStringList() << "Oslo" << "Brisbane" << "Palo Alto" << "Beijing" << "Berlin";
    158.  
    159. void addSampleTableData(QAbstractItemModel * model)
    160. {
    161. if(model->rowCount() == 0)
    162. model->insertRows(0, countries.size());
    163.  
    164. if(model->columnCount() == 0)
    165. model->insertColumns(0, 2);
    166.  
    167. for(int r = 0; r < model->rowCount(); r++)
    168. {
    169. model->setData(model->index(r, 0), countries.at(r));
    170. model->setData(model->index(r, 1), locations.at(r));
    171. }
    172.  
    173. model->setHeaderData(0, Qt::Horizontal, Column1);
    174. model->setHeaderData(1, Qt::Horizontal, Column2);
    175. model->submit();
    176. }
    177.  
    178. QTableView * createView(QAbstractItemModel * model)
    179. {
    180. QTableView * tableView = new QTableView;
    181. tableView->setModel(model);
    182. tableView->setEditTriggers(QTableView::DoubleClicked);
    183. tableView->resizeColumnsToContents();
    184. return tableView;
    185. }
    186.  
    187. int main(int argc, char *argv[])
    188. {
    189. QApplication app(argc, argv);
    190.  
    191. const QString fileName = "Qt.sqlite";
    192. QDir dir;
    193. if(dir.exists(fileName))
    194. if(!dir.remove(fileName))
    195. {
    196. qDebug() << "Unable to delete old Database file " << fileName;
    197. return -1;
    198. }
    199.  
    200. QSqlDatabase sqlDatabase = QSqlDatabase::addDatabase("QSQLITE");
    201. sqlDatabase.setDatabaseName(fileName);
    202.  
    203. if(!sqlDatabase.open())
    204. {
    205. qDebug() << sqlDatabase.lastError().text();
    206. return -2;
    207. }
    208.  
    209. QStandardItemModel standardItemModel;
    210. addSampleTableData(&standardItemModel);
    211.  
    212. QSqlQuery sqlQuery(sqlDatabase);
    213. if(!sqlQuery.exec(QString("CREATE TABLE %1 ( %2 TEXT, %3 TEXT)").arg(TableName).arg(Column1).arg(Column2)))
    214. {
    215. qDebug() << sqlQuery.lastError().text();
    216. return -3;
    217. }
    218.  
    219. QSqlTableModel sqlTableModel(0, sqlDatabase);
    220. sqlTableModel.setTable("Locations");
    221. sqlTableModel.setEditStrategy(QSqlTableModel::OnManualSubmit);
    222. sqlTableModel.select();
    223. addSampleTableData(&sqlTableModel);
    224. sqlTableModel.submitAll();
    225.  
    226. QSqlQueryModel sqlQueryModel;
    227. sqlQueryModel.setQuery(QString("SELECT %2, %3 FROM %1").arg(TableName).arg(Column1).arg(Column2), sqlDatabase);
    228.  
    229. ProxyModel standardItemModelProxy;
    230. standardItemModelProxy.setSourceModel(&standardItemModel);
    231.  
    232. ProxyModel sqlTableModelProxy;
    233. sqlTableModelProxy.setSourceModel(&sqlTableModel);
    234.  
    235. ProxyModel sqlQueryModelProxy;
    236. sqlQueryModelProxy.setSourceModel(&sqlQueryModel);
    237.  
    238. Widget widget;
    239.  
    240. widget.addWidget(0, 0, createView(&standardItemModel), "QStandardItemModel View");
    241. widget.addWidget(0, 1, createView(&sqlTableModel), "QSqlTableModel View");
    242. widget.addWidget(0, 2, createView(&sqlQueryModel), "QSqlQueryModel View");
    243.  
    244. widget.addWidget(1, 0, createView(&standardItemModelProxy), "QStandardItemModel Proxy View");
    245. widget.addWidget(1, 1, createView(&sqlTableModelProxy), "QSqlTableModel Proxy View");
    246. widget.addWidget(1, 2, createView(&sqlQueryModelProxy), "QSqlQueryModel Proxy View");
    247.  
    248. widget.showMaximized();
    249.  
    250. return app.exec();
    251. }
    252.  
    253. #include "main.moc"
    To copy to clipboard, switch view to plain text mode 
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  10. The following user says thank you to Santosh Reddy for this useful post:

    Delphi (29th May 2013)

  11. #9
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,368
    Thanks
    3
    Thanked 5,018 Times in 4,794 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Quote Originally Posted by Santosh Reddy View Post
    Ok, I looked at the ProxyModel in the other post, it looks fine and will works for all QStandardItemModel, QSqlTableModel and QSqlQueryModel (only first column is editable, and other columns are redable)
    I think it won't work with QSortFilterProxyModel because the latter requires proper internal pointers to be present which will not be the case with your implementation. The proper approach is to use QIdentityProxyModel which is able to return proper internal pointers for the source model.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  12. #10
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Quote Originally Posted by wysota
    Quote Originally Posted by Santosh Reddy
    Ok, I looked at the ProxyModel in the other post, it looks fine and will works for all QStandardItemModel, QSqlTableModel and QSqlQueryModel (only first column is editable, and other columns are redable)
    I think it won't work with QSortFilterProxyModel because the latter requires proper internal pointers to be present which will not be the case with your implementation. The proper approach is to use QIdentityProxyModel which is able to return proper internal pointers for the source model.
    I don't think using QIdentityProxyModel will help in any way adding an extra column to the source model. Why do you think it is better than QAbstractItemModel?

    As I see it, as far as adding a virtual column is concerned both QIdentityProxyModel and QAbstractItemModel just the same, you will need to implement index(), columnCount(), mapToSource(), mapFromSource(), data() and setData(). I don't think you can rely on the QIdentityProxyModel's mapToSource() and mapFromSource() as they not aware of the extra column we added, and infact will crash the program as view will try to access the index for the column which does not exist in QIdentityProxyModel nor in sourceModel().

    I agree that the proposed ProxyModel approach will not work when installed on QSortFilterProxyModel, but the other way round will work.
    Ok: QStandardItemModel->ProxyModel->QIdentityModel->QSortFilterProxyModel->QTreeView
    Ok: QSqlTableModel->ProxyModel->QIdentityModel->QSortFilterProxyModel->QTreeView
    Ok: QSqlQueryModel->ProxyModel->QIdentityModel->QSortFilterProxyModel->QTreeView
    FAIL: *->QSortFilterProxyModel->ProxyModel->*
    FAIL: *->QIdentityModel->ProxyModel->*

    Bottom line is that ProxyModel cannot have source model as QSortFilterProxyModel / QIdentityModel, but QSortFilterProxyModel / QIdentityModel can have ProxyModel as source model.

    Here is an example and source.
    ProxyModel_4_Level.jpg
    Attached Files Attached Files
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  13. The following user says thank you to Santosh Reddy for this useful post:

    Delphi (29th May 2013)

  14. #11
    Join Date
    Apr 2013
    Posts
    27
    Thanks
    9
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    my apologies to Santosh Reddy,

    The old and new model work with QSqlTableModel.

    In my code dit not work because there was a QSqlSortfilterModel between the QSqlTableModel and ProxyModel. It was an leftover so it is removed.

    With that in mind i tested the code from Post #8 With an QSortFilterProxyModel.

    ProxyModel -> QSortFilterProxyModel -> 1 of the 3 source models.

    As wysota thought, It is not working.

    But, Testing
    ProxyModel -> QIdentityProxyModel -> 1 of the 3 source models.
    this did not work either.

    So is it possible to make make a ProxyModel that accepts all QAbstractItemModel and its subclasses as source model.


    Added after 1 1:


    Both thanx for helping,

    I think question is partially answered, with this solution it is not gonna work.
    I agree that the proposed ProxyModel approach will not work when installed on QSortFilterProxyModel, but the other way round will work.
    Ok: QStandardItemModel->ProxyModel->QIdentityModel->QSortFilterProxyModel->QTreeView
    Ok: QSqlTableModel->ProxyModel->QIdentityModel->QSortFilterProxyModel->QTreeView
    Ok: QSqlQueryModel->ProxyModel->QIdentityModel->QSortFilterProxyModel->QTreeView
    FAIL: *->QSortFilterProxyModel->ProxyModel->*
    FAIL: *->QIdentityModel->ProxyModel->*
    FAIL: *->ProxyModel->ProxyModel->*
    First is editable second not

    I wil make sure that I am using them in the right order.
    Last edited by Delphi; 29th May 2013 at 09:43.

  15. #12
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    So is it possible to make make a ProxyModel that accepts all QAbstractItemModel and its subclasses as source model.
    To get perfect solution you will be implement a proxy model from QAbstractItemModel, not from QAbstractProxyModel. QAbstractProxyModel expects a one-to-one map between source and proxy.

    When adding extra columns in a proxy model the problem is that column's QModelIndexes will not have a corresponding QModelIndex in source source model. It is simple to assume that the extra column's QModelIndexes will map to QModelIndex() (invalid index) in source but the real problem will arise as there it not way to reach the exrta column's QModelIndexed from source model indexes.
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  16. #13
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,368
    Thanks
    3
    Thanked 5,018 Times in 4,794 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Quote Originally Posted by Santosh Reddy View Post
    As I see it, as far as adding a virtual column is concerned both QIdentityProxyModel and QAbstractItemModel just the same, you will need to implement index(), columnCount(), mapToSource(), mapFromSource(), data() and setData().
    The point is your ProxyModel implementation returns invalid indices for the source model. QIdentityProxyModel is made friend of QAbstractItemModel which lets it call createIndex() on its behalf.

    I don't think you can rely on the QIdentityProxyModel's mapToSource() and mapFromSource() as they not aware of the extra column we added
    You can extend the existing implementation. The point is what I wrote above -- QIdentityProxyModel is friend of QAbstractItemModel so it can return proper indexes for the source model. QAbstractProxyModel can't thus a subclass of QAbstractProxyModel will not either but a subclass of QIdentityProxyModel will.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  17. #14
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Quote Originally Posted by Santosh Reddy
    I don't think you can rely on the QIdentityProxyModel's mapToSource() and mapFromSource() as they not aware of the extra column we added, and infact will crash the program as view will try to access the index for the column which does not exist in QIdentityProxyModel nor in sourceModel().
    Wysota, How do you think QIdentityProxyModel will address this?
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  18. #15
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Here is another example which seems to be perfect solution by inheriting QAbstractItemModel. In this example there is a chain of 9 models connected back to back and 9 view, and the connected as following. Each model has its previous model as source model. The 9 QTableViews viewing each of these models are arranged in a grid layout of 3x3.

    Note the porxy model to add one column is ColumnProxyModel

    1. QStandardItemModel
    2. ColumnProxyModel
    3. QIdentityProxyModel
    4. QSortFilterProxyModel
    5. ColumnProxyModel
    6. QIdentityProxyModel
    7. ColumnProxyModel
    8. ColumnProxyModel
    9. QSortFilterProxyModel

    ColumnProxyModel.jpg
    Attached Files Attached Files
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  19. The following user says thank you to Santosh Reddy for this useful post:

    Delphi (29th May 2013)

  20. #16
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,368
    Thanks
    3
    Thanked 5,018 Times in 4,794 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Quote Originally Posted by Santosh Reddy View Post
    Wysota, How do you think QIdentityProxyModel will address this?
    It will call
    Qt Code:
    1. sourceModel()->createIndex(index.row(), index.column(), index.internalPointer());
    To copy to clipboard, switch view to plain text mode 

    which will preserve:
    • the model
    • row and column
    • implicitly the parent
    • the internal pointer


    Your implementation will only preserve row and column and maybe also the internal pointer. But certainly not the model (thus calling index.data(...) will return wrong values) and probably not the parent.

    You should treat QIdentityProxyModel as a NO-OP, nothing more, nothing less.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  21. #17
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Your implementation will only preserve row and column and maybe also the internal pointer. But certainly not the model (thus calling index.data(...) will return wrong values) and probably not the parent.
    createIndex() is protected, how can we call it on sourceModel()?

    Do you mean QIdentityProxyModel internally calls sourceModel().createIndex()? If yes then my question was not clear.

    Can you give a sample implementation of mapToSouce() and mapFromSource() of the proxy (to add a column) when using QIdentityProxyModel as base class, if you say one does not need to implement these, then how can QIdentityProxyModel know about the extra column and there indexes?

    BTW, a proxy based on QAbstractItemModel in post #15 works well with QSortFilterProxyModel and hopefuly other models too.
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  22. #18
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,368
    Thanks
    3
    Thanked 5,018 Times in 4,794 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    Quote Originally Posted by Santosh Reddy View Post
    createIndex() is protected, how can we call it on sourceModel()?
    As I already said, QIdentityProxyModel is declared friend of QAbstractItemModel so it can call its private methods.

    Can you give a sample implementation of mapToSouce() and mapFromSource() of the proxy (to add a column) when using QIdentityProxyModel as base class,
    It depends on where you want to add the column. If at the end then the default implementation of mapFromSource() is fine and mapToSource() needs to be adjusted to return an invalid index for the artificial column.

    if you say one does not need to implement these, then how can QIdentityProxyModel know about the extra column and there indexes?
    mapFromSource() and mapToSource() don't deal with accessing artificial columns. For that you have to reimplement index() and data().

    By the way, a problem with making a proxy derived from QAbstractItemModel and not QAbstractProxyModel (or its subclass) is that you lose the possibility of going up the chain of proxy models to reach the final model with a single loop, like so:

    Qt Code:
    1. QModelIndex idx = view->currentIndex();
    2. const QAbstractProxyModel *proxy = 0;
    3. while(proxy = qobject_cast<const QAbstractProxyModel*>(idx.model())) {
    4. idx = proxy->mapToSource(idx);
    5. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by wysota; 29th May 2013 at 18:42.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  23. #19
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: 2 subclasses of QSortFilterProxyModel behind each other.

    By the way, a problem with making a proxy derived from QAbstractItemModel and not QAbstractProxyModel (or its subclass) is that you lose the possibility of going up the chain of proxy models to reach the final model with a single loop, like so:
    Yes that is somthing we have take seriously in design, it will be better to subclass QAbstractProxyModel (or its subclass)
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

Similar Threads

  1. Replies: 3
    Last Post: 12th October 2012, 22:42
  2. Creating signals in subclasses
    By Cotlone in forum Newbie
    Replies: 2
    Last Post: 22nd June 2010, 00:16
  3. Why slots in QThread subclasses are unsafe?
    By AlphaWolf in forum Qt Programming
    Replies: 8
    Last Post: 30th May 2010, 15:39
  4. Error creating subclasses
    By agerlach in forum Qt Programming
    Replies: 2
    Last Post: 25th May 2010, 13:49
  5. declaring subclasses in C++
    By Paat in forum Newbie
    Replies: 4
    Last Post: 23rd October 2009, 08:40

Tags for this Thread

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
  •  
Qt is a trademark of The Qt Company.