Results 1 to 7 of 7

Thread: How to filter duplicates from a proxy model.

  1. #1
    Join Date
    Jun 2008
    Posts
    89
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default How to filter duplicates from a proxy model.

    Hi,

    I have a proxy model created from QStandardItem Model. The proxy model has a single row.
    That column contains duplicate entries. I need to populate the QlistView with this model.
    but the Qlist does not need to have duplicates..


    Please help..
    GK

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

    Default Re: How to filter duplicates from a proxy model.

    Use QSortFilterProxyModel::filterAcceptsRow() to filter out duplicate items. You'll also need to connect a custom slot to appropriate signals where you will decide which entries are duplicate so that filterAcceptsRow() can do its job later when it's called.

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

    jfinn88 (12th October 2016)

  4. #3
    Join Date
    Jun 2016
    Posts
    99
    Thanks
    18
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: How to filter duplicates from a proxy model.

    I some what understand that I need filterAcceptsRow() to filter out the duplicate items from my list model for display... but I’m not quite sure how and where to appropriate the signals.... and not sure if I have the function set up properly was hoping you could help me out....

    ------------proxyFilter class-------------
    Qt Code:
    1. //---UserEvent-SortModelProxy | Constructor---//
    2. UserListModelProxy::UserListModelProxy(QObject *parent) : QSortFilterProxyModel(parent){
    3.  
    4. }
    5.  
    6. //---Destructor---//
    7. UserListModelProxy::~UserListModelProxy(){
    8.  
    9. }
    10.  
    11. //---FilterAcceptsRow removes dupicate enteries from userName drop-down list---//
    12. bool UserListModelProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE
    13. {
    14. QModelIndex mindex = sourceModel()->index(sourceRow, 0, sourceParent);
    15. bool validName = (sourceModel()->data(mindex, UserListModel::nameRole)).toBool();
    16. if(validName){
    17. return true;
    18. }else{
    19. return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
    20. }
    21. return false;
    22. }
    23.  
    24. //---The QModelIndex class is used to locate data in a data model | Overrides lessThan()---//
    25. bool UserListModelProxy::lessThan(const QModelIndex &one, const QModelIndex &two) const{
    26.  
    27. //---Sort the ListView model based off the roleType---//
    28. if(sortRole() == UserEventLog::nameRole){
    29. QVariant nameOne = sourceModel()->data(one, UserEventLog::nameRole);
    30. QVariant nameTwo = sourceModel()->data(two, UserEventLog::nameRole);
    31.  
    32. QString str_NameOne = nameOne.toString();
    33. QString str_NameTwo = nameTwo.toString();
    34.  
    35. if (str_NameOne != str_NameTwo){
    36. return str_NameOne < str_NameTwo;
    37. }
    38. else{
    39. //---No Role set returns false---//
    40. return QSortFilterProxyModel::lessThan(one, two);
    41. }
    42. }
    43. else{
    44. return false;
    45. }
    46. }
    To copy to clipboard, switch view to plain text mode 

    ----------model class----------
    Qt Code:
    1. //---userListModel Constructor---//
    2. UserListModel::UserListModel(QObject *parent) : QAbstractListModel(parent){
    3. //---allocates dynamic memory on heap | Instance of proxyModel class---//
    4. m_UserListModelProxy = new UserListModelProxy(this);
    5. m_UserListModelProxy->setSourceModel(this);
    6. m_UserListModelProxy->setDynamicSortFilter(true);
    7. m_UserListModelProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
    8. //m_UserListModelProxy->setSortRole(0);
    9. }
    10.  
    11. //---userListModel Destructor---//
    12. UserListModel::~UserListModel(){
    13.  
    14. }
    15.  
    16. void UserListModel::init(){
    17. dbConnect();
    18. selectEvent();
    19. }
    20.  
    21. //---Function is called in xmui.cpp---//
    22. void UserListModel::setContext(QQmlContext* root){
    23.  
    24. //---Sets rootContext for model to be used in userListModel QML---//
    25. root->setContextProperty("UserListModel", this);
    26. root->setContextProperty("UserListProxy", m_UserListModelProxy);
    27. }
    28.  
    29. //---ProxyModel Sort setRoleName---//
    30. void UserListModel::setSortRole (int role){
    31. switch(role){
    32. case 0:
    33. //---idRole---//
    34. if(m_UserListModelProxy->sortRole() == UserListModel::nameRole){
    35. if(m_UserListModelProxy->sortOrder() == Qt::AscendingOrder)
    36. m_UserListModelProxy->sort(0, Qt::DescendingOrder);
    37. else{
    38. m_UserListModelProxy->sort(0, Qt::AscendingOrder);
    39. }
    40. }
    41. else{
    42. m_UserListModelProxy->setSortRole(UserListModel::nameRole);
    43. m_UserListModelProxy->sort(0);
    44. }
    45. break;
    46. }
    47. }
    48.  
    49. //---Connect to database---//
    50. bool UserListModel::dbConnect(){
    51. //---check if database is connected---//
    52. if(!m_selectDataBase.isValid()){
    53. qDebug() << "error in connecting to DB";
    54. m_selectDataBase = QSqlDatabase::addDatabase("QSQLITE", "conn4");
    55. m_selectDataBase.setDatabaseName(Paths::root() + "/userLog.db");
    56.  
    57. qDebug() << "database connect path: "+Paths::root()+"/userLog.db";
    58. m_selectDataBase.open();
    59. }
    60. else{
    61. qDebug() <<"connected to DB" ;
    62. m_selectDataBase.open();
    63. }
    64. return m_selectDataBase.isValid();
    65. }
    66.  
    67. int UserListModel::rowCount(const QModelIndex &parent) const{
    68. Q_UNUSED(parent);
    69. return m_userList.count();
    70. }
    71.  
    72. QHash<int, QByteArray> UserListModel::roleNames() const{
    73. QHash<int, QByteArray> roleNames;
    74. roleNames.insert(nameRole, "userName");
    75. return roleNames;
    76. }
    77.  
    78. QVariant UserListModel::data(const QModelIndex &index, int role) const{
    79. if (index.row() < 0 || index.row() >= m_userList.count()){
    80. return QVariant();
    81. }
    82.  
    83. QVariant text;
    84.  
    85. if(role == nameRole){
    86. UserList userNames = m_userList.at(index.row());
    87. text = userNames.userName;
    88. }
    89. return text;
    90. }
    91.  
    92. void UserListModel::addEvent(const UserList &userName){
    93. beginInsertRows(QModelIndex(), 0, 0);
    94. m_userList.insert(0, userName);
    95. endInsertRows();
    96. }
    97.  
    98. //---Selects data from DB for display: defualt diplays all Users---//
    99. bool UserListModel::selectEvent(){
    100. dbConnect();
    101. emit showBusy(true);
    102.  
    103. QSqlQuery selectQuery("SELECT userName FROM userlogevents", m_selectDataBase);
    104. if(selectQuery.exec()){
    105. qDebug()<<"UserEventLog::selectEvent() sql statement executed fine";
    106. }
    107. else{
    108. emit xmui->alertMsg(QMessageBox::Warning, "Database Error Message 1", "Error: sql select script..."+selectQuery.lastError().text());
    109. qDebug()<<"UserEventLog::selectEvent() Error with sql statement execution";
    110. return selectQuery.exec();
    111. }
    112.  
    113. UserList userNameList;
    114. beginResetModel();
    115. m_userList.clear();
    116. while (selectQuery.next()){
    117. userNameList.userName = selectQuery.value(0).toString();
    118. addEvent(userNameList);
    119. }
    120. endResetModel();
    121. emit showBusy(false);
    122. m_selectDataBase.close();
    123. return selectQuery.exec();
    124. }
    To copy to clipboard, switch view to plain text mode 

    --------QML code--------
    Qt Code:
    1. //---Calls dbConnect(), archiveEvent() & selectEvent() functions after QML loads---//
    2. Component.onCompleted: {
    3. //---calls constructors sets proxy source---//
    4. UserEventLog.init();
    5. //---loads userName dropDwon---//
    6. UserListModel.init();
    7. listView.currentIndex = 0
    8. listView.positionViewAtBeginning();
    9. listView.forceActiveFocus();
    10. }
    11.  
    12. //-------------------------------------------------------------//
    13.  
    14. //---List UserNames Currently in the database---//
    15. ComboBox {
    16. id: userNameDropDown
    17. implicitHeight: 40
    18. implicitWidth: 130
    19. KeyNavigation.tab: beginDateTextField
    20. activeFocusOnTab: true
    21. model: UserListModel
    22. textRole: "userName"
    23. style: userListCombo
    24. Keys.onReturnPressed: {
    25. userNameDropDown.focus = false;
    26. beginDateTextField.focus = true;
    27. beginDateTextField.selectAll();
    28. }
    29. }
    To copy to clipboard, switch view to plain text mode 

  5. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to filter duplicates from a proxy model.

    Question: do you need the duplicates or original sort order in a different place at the same time?
    If not, you could simply sort and de-deduplicate in the model itself.

    Cheers,
    _

  6. #5
    Join Date
    Jun 2016
    Posts
    99
    Thanks
    18
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: How to filter duplicates from a proxy model.

    No I don’t need the duplicates or the original sort order...

    wouldn't you need the virtual functions of the proxy to preform or override the sort() or filterAcceptsRow(), I'm not sure how to do that in the model....

  7. #6
    Join Date
    Jun 2016
    Posts
    99
    Thanks
    18
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: How to filter duplicates from a proxy model.

    updated code for filterAcceptsRow()

    Qt Code:
    1. //---FilterAcceptsRow removes duplicate enteries from userName drop-down list---//
    2. bool UserListModelProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE
    3. {
    4. //---Returns the index of the source model item in the model specified by the given row, column and parent index---//
    5. QModelIndex mindex = sourceModel()->index(sourceRow, 0, sourceParent);
    6. qDebug() << "UserListModelProxy::filterAcceptsRow mindex:" << mindex;
    7.  
    8. //---Returns the data stored under the given role for the item referred to by the index---//
    9. bool validName = (sourceModel()->data(mindex, UserListModel::nameRole)).toBool();
    10. qDebug() << "UserListModelProxy::filterAcceptsRow validName:" << validName;
    11.  
    12. if(validName){
    13. bool filterRow1 = QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
    14. qDebug() << "UserListModelProxy::filterAcceptsRow filterRow1:" << filterRow1;
    15.  
    16. //---Returns true if the item is to be included in the model---//
    17. if(QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent)){
    18. bool filterRow2 = QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
    19. qDebug() << "UserListModelProxy::filterAcceptsRow filterRow2:" << filterRow2;
    20. return true;
    21. }
    22. else{
    23. //---Sets the role data item for the source Model item at index to value | Returns true if successful; otherwise returns false---//
    24. sourceModel()->setData(mindex, false, UserListModel::nameRole);
    25. }
    26. }
    27. return false;
    28. }
    To copy to clipboard, switch view to plain text mode 


    Added after 1 3 minutes:


    Solution:

    I got some help and realized I could pull out distinct records from database into model with a sql script using keyword "distinct" works great and I don't have to implement another class for filtering

    Qt Code:
    1. QSqlQuery selectQuery("SELECT DISTINCT userName FROM userlogevents", m_selectDataBase);
    To copy to clipboard, switch view to plain text mode 

    although I would like to know how to properly set up and override the filterAcceptsRow() I'm just confused how to set-up the condition checking to remove duplicate entries. I know I need to set the source models index use that index to get the source models data then I need to check if the userName pulled out is unique but not sure how to do that part of the condition to return false to remove it form the model.....

    Qt Code:
    1. //---FilterAcceptsRow removes duplicate enteries from userName drop-down list---//
    2. bool UserListModelProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE
    3. {
    4. //---Sets index of the source model--//
    5. QModelIndex mindex = sourceModel()->index(sourceRow, 0, sourceParent);
    6.  
    7. //---Sets sourceModel data | Returns data stored under the given role referred to by the index---//
    8. bool validName = (sourceModel()->data(mindex, UserListModel::nameRole)).toBool();
    9.  
    10. //---not sure how to set up condition to remove non unique userNames from model---//
    11.  
    12. //---Check to see if data is valid---//
    13. if(//check for unique userName){
    14. return //boolValue;
    15. }
    16. else{
    17. /* Returns true if the item in the row
    18.   * indicated by the given source_row and
    19.   * source_parent should be included in the model
    20.   */
    21. return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
    22. }
    23. return false;
    24. }
    To copy to clipboard, switch view to plain text mode 


    note: I will index my userName column in my database to try to improve search speeds
    Last edited by jfinn88; 13th October 2016 at 23:08.

  8. #7
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to filter duplicates from a proxy model.

    Quote Originally Posted by jfinn88 View Post
    No I don’t need the duplicates or the original sort order...
    Then I would definitely do that in the model directly.

    Quote Originally Posted by jfinn88 View Post
    wouldn't you need the virtual functions of the proxy to preform or override the sort() or filterAcceptsRow(), I'm not sure how to do that in the model....
    No, a proxy is only required if the model itself needs to contain all data and you need to have the sorting and filtering on top of that.
    E.g. because the model can't be changed at all or the full/unsorted data is needed as well.

    In a custom model, especially one that contains a copy of the data like yours, you can easily sort/filter the data directly.

    But that's really off-topic for this thread.

    Cheers,
    _

Similar Threads

  1. A few queries about Model View Programming
    By montylee in forum Qt Programming
    Replies: 46
    Last Post: 2nd March 2009, 09:36
  2. Custom proxy model issue
    By Khal Drogo in forum Qt Programming
    Replies: 13
    Last Post: 30th November 2007, 13:41
  3. Model and Proxy
    By larry104 in forum Qt Programming
    Replies: 1
    Last Post: 4th August 2006, 22:05

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.