Results 1 to 4 of 4

Thread: Problems with QSortFilterProxyModel and QTableView

  1. #1
    Join Date
    Mar 2013
    Posts
    5
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Problems with QSortFilterProxyModel and QTableView

    Hi to all.

    I'm quite a newbie; I've been learning and developing in Qt 4.8.4 for just three weeks now. I have to say that I'm very impressed with the power of this platform!

    I'm developing a very simple widget that must show a list of image files. To do it, I have used derivatives of Qt classes QTableView, QAbstractTableModel as well as a QSortFilterProxyModel.

    The widget is composed of a single toolbar at the top and the table view just below.

    The toolbar has two buttons: add and delete. The add button opens a file selector (with multiple selection enabled); the files thus selected are added to the table view below. Obviously, the delete button is enabled only when a row in the table view is selected. When clicked, removes the corresponding entry (row) from the table view.

    Since I want to provide the ability to sort the rows in the view, I have used a QSortFilterProxyModel.

    The problem arises when I want to delete a row from the table view. Since I'm using a filter, I translate the row number returned by the selection event from indices valid for the filter to those valid to my backend structure (a simple QStringList).

    Normally, this translation works pretty well, so deletion works also fine.

    But I have noticed that, depending on how are the names of the files added to the list, the index translation goes crazy!

    For instance, if all the files loaded in the table view adhere to the pattern "DSC999999" (where '9' stands for a digit) my software works flawlessly. But if other type of file names enter the game, then the index translation procedure fails miserably. For instance, with filenames as "h02_0698_08-15_mar200.tif" this strange behaviour appears. The index translation fails and the row removed is not the correct one.

    I wonder if this can be produced by different string codification / locales (UTF, Latin-1...). Since these filenames are obtained using a QFileDialog object that scans my disk, and my Windows 7 is an spanish version... could this explain that the sort filter would behave in such a strange way? If not, could any one take a look to my code and point to the offending / bad code?

    I have included the .cpp files that are involved in this problem. I don't include the .hpp(s) because otherwise this message becomes to long and the forum system does not accept it.

    Thank you very much in advance for your help!

    THE FILES

    ImageListModel.cpp

    Qt Code:
    1. #include "ImageListModel.hpp"
    2.  
    3. bool
    4. ImageListModel::
    5. appendRow
    6. (QString& filename)
    7. {
    8. {
    9. int position = filenames_->size();
    10.  
    11. beginInsertRows(QModelIndex(), position, position);
    12. filenames_->append(filename);
    13. endInsertRows();
    14.  
    15. return true;
    16. }
    17. }
    18.  
    19. ImageListModel::
    20. ImageListModel
    21. (QStringList *filenames,
    22. QObject *parent) : QAbstractTableModel(parent)
    23. {
    24. {
    25. filenames_ = filenames;
    26. }
    27. }
    28.  
    29. bool
    30. ImageListModel::
    31. removeRow
    32. (int position)
    33. {
    34. {
    35. beginRemoveRows(QModelIndex(), position, position);
    36. filenames_->removeAt(position);
    37. endRemoveRows();
    38.  
    39. return true;
    40. }
    41. }
    42.  
    43. int
    44. ImageListModel::
    45. rowCount(const QModelIndex &parent ) const
    46. {
    47. {
    48. Q_UNUSED(parent);
    49. return filenames_->count();
    50. }
    51. }
    52.  
    53. int
    54. ImageListModel::
    55. columnCount(const QModelIndex &parent ) const
    56. {
    57. {
    58. Q_UNUSED(parent);
    59. return 2;
    60. }
    61. }
    62.  
    63. ImageListModel::
    64. headerData(int section,
    65. Qt::Orientation orientation,
    66. int role) const
    67. {
    68. if (orientation == Qt::Horizontal)
    69. {
    70. if (role == Qt::DisplayRole)
    71. {
    72. switch (section)
    73. {
    74. case 0:
    75. return tr("Image name");
    76. case 1:
    77. return tr("Path");
    78. default:
    79. return QVariant();
    80. }
    81. }
    82. }
    83. return QAbstractTableModel::headerData(section, orientation, role);
    84. }
    85.  
    86. ImageListModel::
    87. data(const QModelIndex &index,
    88. int role) const
    89. {
    90. if (!index.isValid()) return QVariant();
    91.  
    92. if (index.row() >= filenames_->size() || index.row() < 0)
    93. return QVariant();
    94.  
    95. QFileInfo fi = filenames_->at(index.row());
    96.  
    97. if (role == Qt::DisplayRole || role == Qt::EditRole)
    98. {
    99. switch (index.column())
    100. {
    101. case 0:
    102. return fi.fileName(); // File name.
    103. case 1:
    104. return fi.path(); // File path.
    105. default:
    106. return QVariant();
    107. }
    108. }
    109.  
    110. return QVariant();
    111. }
    To copy to clipboard, switch view to plain text mode 

    ImageTableView.cpp

    Qt Code:
    1. #include "ImageTableView.hpp"
    2.  
    3. ImageTableView::
    4. ImageTableView
    5. (QWidget *parent) :
    6. QTableView(parent)
    7. {
    8. {
    9. connect(this,SIGNAL(clicked(QModelIndex)),this,SLOT(clickedSlot(QModelIndex)));
    10. }
    11. }
    12.  
    13. void
    14. ImageTableView::
    15. clickedSlot
    16. {
    17. {
    18. emit rowSelected(qi.row());
    19. }
    20. }
    To copy to clipboard, switch view to plain text mode 

    ImageListManager.hpp

    Qt Code:
    1. #ifndef IMAGELISTMANAGER_HPP
    2. #define IMAGELISTMANAGER_HPP
    3.  
    4. #include <QWidget>
    5. #include <QStringList>
    6. #include <QAction>
    7. #include <QSortFilterProxyModel>
    8. #include <QVBoxLayout>
    9. #include <QToolBar>
    10. #include <QHeaderView>
    11. #include <QFileDialog>
    12.  
    13. #include "ImageListModel.hpp"
    14. #include "ImageTableView.hpp"
    15.  
    16. class ImageListManager : public QWidget
    17. {
    18. Q_OBJECT
    19.  
    20. public:
    21.  
    22. ImageListManager(QWidget *parent = 0);
    23.  
    24. protected slots:
    25.  
    26. void addImages(void);
    27. void deleteSelectedRow (void);
    28. void rowSelected(int rowIndex);
    29.  
    30. protected:
    31.  
    32. QAction* actionAddImages_;
    33. QAction* actionRemoveImage_;
    34. int cur_row_;
    35. QStringList filenames_;
    36. ImageListModel* model_;
    37. QSortFilterProxyModel* proxyModel_;
    38. ImageTableView* tableView_;
    39.  
    40. };
    41.  
    42. #endif // IMAGELISTMANAGER_HPP
    To copy to clipboard, switch view to plain text mode 

    ImageListManager.cpp

    Qt Code:
    1. #include "ImageListManager.hpp"
    2.  
    3. void
    4. ImageListManager::
    5. addImages
    6. (void)
    7. {
    8. {
    9. QFileDialog dialog(this);
    10. dialog.setFileMode(QFileDialog::ExistingFiles);
    11. dialog.setNameFilter(trUtf8( "Image Files (*.bmp *.jpg *.jpeg *.png *.tif);;Any Files (*.*)"));
    12.  
    13. if (dialog.exec())
    14. {
    15. int i;
    16. QStringList fileNames = dialog.selectedFiles();
    17.  
    18. for (i = 0; i < fileNames.size(); i++)
    19. {
    20. QString* file = new QString(fileNames.at(i));
    21. model_->appendRow(*file);
    22. delete file;
    23. }
    24.  
    25. tableView_->resizeColumnsToContents();
    26. }
    27. }
    28. }
    29.  
    30. void
    31. ImageListManager::
    32. deleteSelectedRow
    33. (void)
    34. {
    35. {
    36.  
    37. if (cur_row_ < 0) return;
    38. if (cur_row_ >= filenames_.size()) return;
    39.  
    40. QModelIndex source = model_->index(cur_row_,0);
    41. QModelIndex sorted = proxyModel_->mapFromSource(source);
    42.  
    43.  
    44. //
    45. // Now we may delete the filename from the list, since we know
    46. // the real position affected.
    47. //
    48.  
    49. model_->removeRow(sorted.row());
    50.  
    51.  
    52. // Reset things.
    53.  
    54. tableView_->clearSelection();
    55. cur_row_ = -1;
    56. actionRemoveImage_->setEnabled(false);
    57. }
    58. }
    59.  
    60. ImageListManager::
    61. ImageListManager
    62. (QWidget *parent) : QWidget(parent)
    63. {
    64. {
    65. // Initialize some members.
    66.  
    67. cur_row_ = -1;
    68.  
    69. // Create the toolbar, including its actions.
    70.  
    71. QToolBar* imageListToolBar = new QToolBar(tr("Image list toolbar"), this);
    72. imageListToolBar->setMovable(false);
    73.  
    74. QIcon removeImageIcon;
    75. removeImageIcon.addFile(QString::fromUtf8(":/resources/delete.png"), QSize(), QIcon::Normal, QIcon::Off);
    76. actionRemoveImage_ = new QAction(removeImageIcon, tr("Remove image"), this);
    77. actionRemoveImage_->setEnabled(false);
    78. connect(actionRemoveImage_, SIGNAL(triggered()), this, SLOT(deleteSelectedRow()));
    79. imageListToolBar->addAction(actionRemoveImage_);
    80.  
    81. QIcon newImagesIcon;
    82. newImagesIcon.addFile(QString::fromUtf8(":/resources/add.png"), QSize(), QIcon::Normal, QIcon::Off);
    83. actionAddImages_ = new QAction(newImagesIcon, tr("Add images"), this);
    84. actionAddImages_->setEnabled(true);
    85. connect(actionAddImages_, SIGNAL(triggered()), this, SLOT(addImages()));
    86. imageListToolBar->addAction(actionAddImages_);
    87.  
    88.  
    89. // Create the files model that will backing the table view.
    90.  
    91. model_ = new ImageListModel(&filenames_, this);
    92.  
    93. // Create the proxy model to sort data.
    94.  
    95. proxyModel_ = new QSortFilterProxyModel(this);
    96. proxyModel_->setSortCaseSensitivity(Qt::CaseInsensitive);
    97. proxyModel_->setDynamicSortFilter(true);
    98. proxyModel_->setSortLocaleAware(true);
    99. proxyModel_->setSourceModel(model_); // Sort the data in model_
    100.  
    101. // Set up the table view for the points.
    102.  
    103. tableView_ = new ImageTableView(this);
    104. tableView_->setModel(proxyModel_); // proxyModel_ instead of model_!!!
    105. tableView_->setSortingEnabled(true);
    106. tableView_->setSelectionBehavior(QAbstractItemView::SelectRows);
    107. tableView_->setSelectionMode(QAbstractItemView::SingleSelection);
    108. tableView_->verticalHeader()->hide();
    109.  
    110. //proxyModel_->sort(0, Qt::DescendingOrder);
    111.  
    112. // Lay out the toolbar and table view.
    113.  
    114. QVBoxLayout *mainLayout = new QVBoxLayout;
    115. mainLayout->addWidget(imageListToolBar);
    116. mainLayout->addWidget(tableView_);
    117. setLayout(mainLayout);
    118.  
    119. // Connect events coming from the table view.
    120.  
    121. connect(tableView_, SIGNAL(rowSelected(int)), this, SLOT(rowSelected(int)));
    122.  
    123. // Set the window title.
    124.  
    125. setWindowTitle(tr("Images in project"));
    126.  
    127. }
    128. }
    129.  
    130. void
    131. ImageListManager::
    132. rowSelected
    133. (int rowIndex)
    134. {
    135. {
    136. actionRemoveImage_->setEnabled(true);
    137. cur_row_ = rowIndex;
    138. }
    139. }
    To copy to clipboard, switch view to plain text mode 

    Just for the sake of completeness, I post here the .hpp files that wouldn't fit in the previous post.

    ImageListModel.hpp

    Qt Code:
    1. #ifndef IMAGELISTMODEL_HPP
    2. #define IMAGELISTMODEL_HPP
    3.  
    4. #include <QAbstractTableModel>
    5. #include <QStringList>
    6. #include <QFileInfo>
    7.  
    8. class ImageListModel : public QAbstractTableModel
    9. {
    10. public:
    11. bool appendRow (QString& filename);
    12. int columnCount(const QModelIndex &parent ) const;
    13. QVariant data(const QModelIndex &index, int role) const;
    14. QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    15. ImageListModel(QStringList* filenames, QObject *parent=0);
    16. bool removeRow (int position);
    17. int rowCount(const QModelIndex &parent ) const;
    18.  
    19. protected:
    20.  
    21. QStringList* filenames_;
    22. };
    23.  
    24. #endif // IMAGELISTMODEL_HPP
    To copy to clipboard, switch view to plain text mode 

    ImageTableView.hpp

    Qt Code:
    1. #ifndef IMAGETABLEVIEW_HPP
    2. #define IMAGETABLEVIEW_HPP
    3.  
    4. #include <QTableView>
    5.  
    6. class ImageTableView : public QTableView
    7. {
    8. Q_OBJECT
    9.  
    10. public:
    11.  
    12. explicit ImageTableView(QWidget *parent = 0);
    13.  
    14. signals:
    15.  
    16. void rowSelected(int rowIndex);
    17.  
    18. public slots:
    19.  
    20. void clickedSlot(QModelIndex qi);
    21.  
    22. };
    23.  
    24. #endif // IMAGETABLEVIEW_HPP
    To copy to clipboard, switch view to plain text mode 

    ImageListManager.hpp

    Qt Code:
    1. #ifndef IMAGELISTMANAGER_HPP
    2. #define IMAGELISTMANAGER_HPP
    3.  
    4. #include <QWidget>
    5. #include <QStringList>
    6. #include <QAction>
    7. #include <QSortFilterProxyModel>
    8. #include <QVBoxLayout>
    9. #include <QToolBar>
    10. #include <QHeaderView>
    11. #include <QFileDialog>
    12.  
    13. #include "ImageListModel.hpp"
    14. #include "ImageTableView.hpp"
    15.  
    16. class ImageListManager : public QWidget
    17. {
    18. Q_OBJECT
    19.  
    20. public:
    21.  
    22. ImageListManager(QWidget *parent = 0);
    23.  
    24. protected slots:
    25.  
    26. void addImages(void);
    27. void deleteSelectedRow (void);
    28. void rowSelected(int rowIndex);
    29.  
    30. protected:
    31.  
    32. QAction* actionAddImages_;
    33. QAction* actionRemoveImage_;
    34. int cur_row_;
    35. QStringList filenames_;
    36. ImageListModel* model_;
    37. QSortFilterProxyModel* proxyModel_;
    38. ImageTableView* tableView_;
    39.  
    40. };
    41.  
    42. #endif // IMAGELISTMANAGER_HPP
    To copy to clipboard, switch view to plain text mode 
    Last edited by bleriot13; 11th March 2013 at 15:30.

  2. #2
    Join Date
    Feb 2008
    Posts
    491
    Thanks
    12
    Thanked 142 Times in 135 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Problems with QSortFilterProxyModel and QTableView

    Looks to me like you have the following backwards:
    Qt Code:
    1. QModelIndex source = model_->index(cur_row_,0);
    2. QModelIndex sorted = proxyModel_->mapFromSource(source);
    To copy to clipboard, switch view to plain text mode 
    You are selecting from your proxy model and want to delete in the source model, right? Try:
    Qt Code:
    1. QModelIndex index = proxyModel_->index(cur_row_,0);
    2. QModelIndex sorted = proxyModel_->mapToSource(index);
    To copy to clipboard, switch view to plain text mode 

  3. #3
    Join Date
    Mar 2013
    Posts
    5
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Windows

    Default Solved: Problems with QSortFilterProxyModel and QTableView

    Norobro,

    thank you very much. Your hint worked as a charm! Just one minute work and everything behaves as it must!

    I got really confused because my translation seemed to work well when I didn't include some kind of file names in the list. In fact, I have implemented another widget including a similar list, including not files but identifiers, that has been coded using the same technique shown in the files I included and it has been working flawlessly. That's what made me think of a possible problem in the sorting / indexing mechanism in the proxy model. I'll correct this other widget too and check it.

    Thanks a lot!!!

    Bleriot
    Last edited by bleriot13; 12th March 2013 at 07:54. Reason: Problem solved

  4. #4
    Join Date
    Mar 2014
    Posts
    25
    Thanks
    12
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Solved: Problems with QSortFilterProxyModel and QTableView

    thanks alot for this subject it helps me..

Similar Threads

  1. QTableView with QSortFilterProxyModel
    By TheGrimace in forum Qt Programming
    Replies: 4
    Last Post: 13th November 2012, 15:38
  2. Problem with QTableView and QSortFilterProxyModel
    By unix7777 in forum Qt Programming
    Replies: 7
    Last Post: 24th August 2012, 08:11
  3. Replies: 6
    Last Post: 22nd November 2011, 03:53
  4. Replies: 2
    Last Post: 10th May 2010, 13:13
  5. Problems with QSortFilterProxyModel
    By Nefastious in forum Newbie
    Replies: 10
    Last Post: 31st October 2009, 18:51

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.