Results 1 to 4 of 4

Thread: QSortFilterProxyModel trouble - corrupting (dublicating) data in table

  1. #1
    Join Date
    Dec 2008
    Posts
    32
    Thanks
    17
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default QSortFilterProxyModel trouble - corrupting (dublicating) data in table

    Here is another difficult (for me) thing with using QSortFilterProxyModel.
    I have custom Delegate, custom Model, standard QTableView, standard QSortFilterProxyModel.

    My custom Delegate provides a widget (based on QDialog) for editing whole row of data at once.
    Widget appears on display, user edits LineEdits, then all data is updating. Works well.
    But it works only if you don't use sorting. After sorting, rows are lined up in some order, but if we edit a row now, there are some bugs - edited row is dublicated - one with old data and another one with new. I think that's because of incorrect applying of QSortFilterProxyModel. Would you please look at my code to help me find out what's wrong.

    main window:
    Qt Code:
    1. Eve::Eve(QWidget* parent): QMainWindow(parent) {
    2. setupUi(this); readSettings();
    3.  
    4. eveModel = new EveModel(this);
    5.  
    6. proxyModel = new QSortFilterProxyModel(this);
    7. proxyModel->setSourceModel(eveModel);
    8. proxyModel->setDynamicSortFilter(true);
    9.  
    10. tableView->setModel(proxyModel);
    11.  
    12. header = tableView->horizontalHeader();
    13. header->setModel(eveModel);
    14.  
    15. eveDelegate = new EveDelegate(this, eveModel, proxyModel);
    16. tableView->setItemDelegate(eveDelegate);
    17. }
    18.  
    19. void Eve::insertRow() {
    20. eveModel->insertRows(eveModel->rowCount(), 1);
    21. }
    22.  
    23. void Eve::removeRow() {
    24. eveModel->removeRows(tableView->selectionModel()->currentIndex().row(), 1);
    25. }
    To copy to clipboard, switch view to plain text mode 

    Main methods of Delegate:
    Qt Code:
    1. QWidget *EveDelegate::createEditor ( QWidget *parent,
    2. const QStyleOptionViewItem& option,
    3. const QModelIndex& /* index */ ) const
    4. {
    5. uEditor* editor = new uEditor ( parent ); // my class based on QDialog
    6. return editor;
    7. }
    8.  
    9. void EveDelegate::setEditorData ( QWidget *e,
    10. const QModelIndex &index ) const
    11. {
    12. // ugly but works
    13. QModelIndex index_sibling0 = index.sibling ( index.row(), 0 ); // Variable
    14. QVariant variable = index_sibling0.model()->data ( index_sibling0, Qt::DisplayRole );
    15. QModelIndex index_sibling1 = index.sibling ( index.row(), 1 ); // Value
    16. QVariant value = index_sibling1.model()->data ( index_sibling1, Qt::DisplayRole );
    17. QModelIndex index_sibling4 = index.sibling ( index.row(), 4 ); // placeToSave
    18. QString placeToSave = index_sibling4.model()->data ( index_sibling4, Qt::DisplayRole ).toString();
    19. uEditor *editor = static_cast<uEditor*> ( e );
    20. editor->valueEdit->setPlainText ( value.toString() );
    21. editor->variableEdit->setText ( variable.toString() );
    22. if( "global" == placeToSave )
    23. editor->checkBox->setChecked(true);
    24. else
    25. editor->checkBox->setChecked(false);
    26. }
    27.  
    28. void EveDelegate::setModelData (
    29. QWidget *e,
    30. const QModelIndex& index ) const
    31. {
    32. uEditor *editor = static_cast<uEditor*> ( e );
    33.  
    34. // getting values from Widget
    35. QString value = editor->valueEdit->toPlainText();
    36. QString variable = editor->variableEdit->text();
    37. QString placeToSave;
    38. if ( editor->checkBox->isChecked() )
    39. placeToSave = "global";
    40. else
    41. placeToSave = "local";
    42. eveModel->setData ( index, variable, value, placeToSave, value );
    43. }
    To copy to clipboard, switch view to plain text mode 

    and Model's :

    Qt Code:
    1. bool EveModel::setData ( const QModelIndex& index,
    2. const QString variable,
    3. const QString value,
    4. const QString placeToSave,
    5. const QString initValue,
    6. int role )
    7. {
    8. if ( index.isValid() )
    9. {
    10. if ( ( *m_records ) [index.row() +1][6].isEmpty() )
    11. ( *m_records ) [index.row() +1][6] = ( *m_records ) [index.row() +1][1];
    12. ( *m_records ) [index.row() +1][0] = variable;
    13. ( *m_records ) [index.row() +1][1] = value;
    14. ( *m_records ) [index.row() +1][4] = placeToSave;
    15. emit dataChanged ( index.sibling ( index.row()+1, 0 ), index.sibling ( index.row()+1, 6 ) );
    16. reset();
    17. return true;
    18. }
    19. return false;
    20. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Dec 2008
    Posts
    32
    Thanks
    17
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QSortFilterProxyModel trouble - corrupting (dublicating) data in table

    Also, when I'm calling removeRows() method the message appears in console:
    "QSortFilterProxyModel: inconsistent changes reported by source model".
    But the method seems to be working.

    Here are 2 variants of removeRows() method:
    Qt Code:
    1. void Eve::removeRow() {
    2. eveModel->removeRows(tableView->selectionModel()->currentIndex().row(), 1);
    3. }
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. void Eve::removeRow() {
    2. QModelIndex index = proxyModel->mapToSource(tableView->selectionModel()->currentIndex());
    3. eveModel->removeRows(index.row(), 1);
    4. }
    To copy to clipboard, switch view to plain text mode 

  3. #3
    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: QSortFilterProxyModel trouble - corrupting (dublicating) data in table

    Could we see implementation of the model?

  4. #4
    Join Date
    Dec 2008
    Posts
    32
    Thanks
    17
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QSortFilterProxyModel trouble - corrupting (dublicating) data in table

    Of course!

    evemodel.cpp:
    Qt Code:
    1. #include "evemodel.h"
    2. #include <QProcess>
    3. #include <QSize>
    4.  
    5. EveModel::EveModel(QObject* parent /* = 0 */ )
    6. : QAbstractTableModel(parent) {
    7. m_headers = new QStringList();
    8. *m_headers << tr("Variable") << tr("Value") << tr("Origin") << tr("Description");
    9. m_records = new QList<QStringList>();
    10. m_delvars = new QList<QStringList>();
    11. initListFromMem(*m_records);
    12. }
    13.  
    14. int EveModel::rowCount(const QModelIndex& parent /*=QModelIndex() */) const {
    15. if( parent.isValid() || ( m_records->count() == 0 ) )
    16. return 0;
    17. else
    18. return m_records->count() - 1;
    19. }
    20.  
    21. int EveModel::columnCount(const QModelIndex& parent /*=QModelIndex()*/ ) const {
    22. Q_UNUSED(parent);
    23. if ( m_records->count() )
    24. return 7;
    25. else
    26. return 0;
    27. }
    28.  
    29. QVariant EveModel::data(const QModelIndex& index, int role /* =Qt::DisplayRole */ ) const {
    30. if ( !index.isValid() || !m_records->count() )
    31. return QVariant();
    32. QStringList record = m_records->at(index.row()+1);
    33. if ( role == Qt::DisplayRole || role == Qt::EditRole )
    34. return record.at(index.column());
    35. if ( role == Qt::ToolTipRole ) {
    36. QString tip, key, value;
    37. tip = "<table>";
    38. //int maxLines = record.count();
    39. for (int i = 0; i < 4/*maxLines*/; i++) {
    40. key = headerData(
    41. i, Qt::Horizontal, Qt::DisplayRole).toString();
    42. value = record.at(i);
    43. if (!value.isEmpty())
    44. tip += QString("<tr><td><b>%1</b>: %2</td></tr>").arg(key, value);
    45. }
    46. tip += "</table>";
    47. return tip;
    48. }
    49. return QVariant();
    50. }
    51.  
    52. Qt::ItemFlags EveModel::flags(const QModelIndex &index) const {
    53. if ( !index.isValid() || !m_records->count() )
    54. return 0;
    55. return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
    56. }
    57.  
    58. bool EveModel::setData ( const QModelIndex& index, const QVariant& value, int role /*=Qt::EditRole */ )
    59. {
    60. if ( index.isValid() && ( role == Qt::EditRole ) )
    61. {
    62. if ( ( *m_records ) [index.row() +1][6].isEmpty() )
    63. ( *m_records ) [index.row() +1][6] = ( *m_records ) [index.row() +1][index.column() ];
    64. ( *m_records ) [index.row() +1][index.column() ] = value.toString();
    65. emit dataChanged ( index, index );
    66. return true;
    67. }
    68. return false;
    69. }
    70.  
    71. bool EveModel::setData ( const QModelIndex& index,
    72. const QString variable,
    73. const QString value,
    74. const QString placeToSave,
    75. const QString initValue,
    76. int role )
    77. {
    78. if ( index.isValid() )
    79. {
    80. if ( ( *m_records ) [index.row() +1][6].isEmpty() )
    81. ( *m_records ) [index.row() +1][6] = ( *m_records ) [index.row() +1][1];
    82. ( *m_records ) [index.row() +1][0] = variable;
    83. ( *m_records ) [index.row() +1][1] = value;
    84. ( *m_records ) [index.row() +1][4] = placeToSave;
    85. emit dataChanged ( index.sibling ( index.row()+1, 0 ), index.sibling ( index.row()+1, 6 ) );
    86. reset();
    87. return true;
    88. }
    89. return false;
    90. }
    91.  
    92. QVariant EveModel::headerData(int section, Qt::Orientation orientation, int role /* =Qt::DisplayRole */ ) const {
    93.  
    94. if (orientation == Qt::Horizontal) {
    95. if (role == Qt::DisplayRole)
    96. return m_headers->count() > section ? m_headers->at(section) : QAbstractTableModel::headerData(section, orientation, role);
    97. if (role == Qt::SizeHintRole) {
    98. return QSize(1, 30);
    99. }
    100. }
    101. else if (orientation == Qt::Vertical) {
    102. if (role == Qt::DisplayRole)
    103. return QVariant();
    104. }
    105. return QAbstractTableModel::headerData(section, orientation, role);
    106. }
    107.  
    108.  
    109.  
    110. EveModel::~EveModel() {
    111. m_headers->clear();
    112. delete m_headers;
    113. m_delvars->clear();
    114. delete m_delvars;
    115. m_records->clear();
    116. delete m_records;
    117. }
    118.  
    119. void EveModel::initListFromMem(QList<QStringList>& outputList) {
    120. outputList.clear();
    121. QStringList sysvars = QProcess::systemEnvironment();
    122. QRegExp rx("([a-zA-Z0-9_]+)=(.+)");
    123. foreach( QString str, sysvars)
    124. {
    125. rx.indexIn(str);
    126. QStringList list = rx.capturedTexts();
    127. if (!list.isEmpty())
    128. {
    129. list.removeFirst();
    130. if ( !list.at(0).isEmpty() ) {
    131. list << tr("System");
    132. setDescription(list);
    133. list << tr("local");
    134. list << tr("");
    135. list << tr("");
    136. outputList.append(list);
    137. }
    138. }
    139. }
    140. }
    141.  
    142. void EveModel::setDescription(QStringList& list) {
    143. if ("HOME" == list.at(0)) {
    144. //this->homePath = list.at(1);
    145. list << tr("This is the path to the home directory");
    146. }
    147. else if ("LOGNAME" == list.at(0)) {
    148. //if( "root" == list.at(1) )
    149. // this->isRoot = true;
    150. list << tr("This is your logname");
    151. }
    152. else if ("SHELL" == list.at(0)) {
    153. //if( "/bin/bash" == list.at(1) )
    154. // this->isBash = true;
    155. list << tr("Your shell");
    156. }
    157. else
    158. list << tr("");
    159. }
    160.  
    161. bool EveModel::insertRows(int row, int count, const QModelIndex& parent /* =QModelIndex()*/){
    162. Q_UNUSED(parent);
    163. QStringList emptyRecord;
    164. emptyRecord << tr("NEW") << tr("VALUE") << tr("System") << tr("") << tr("") << tr("") << tr("");
    165. beginInsertRows(QModelIndex(), row, row);
    166. m_records->append(emptyRecord);
    167. endInsertRows();
    168. return true;
    169. }
    170.  
    171. bool EveModel::removeRows( int row, int count, const QModelIndex& parent) {
    172. //Q_UNUSED(parent);
    173. beginRemoveRows(QModelIndex(), row, row+1);
    174. if( (m_records->at(row+1)).at(3) != "System")
    175. m_delvars->append(m_records->at(row+1));
    176. m_records->removeAt(row+1);
    177. reset();
    178. endRemoveRows();
    179. if ( !parent.isValid() || m_records->count() == 0)
    180. emit disableDel();
    181.  
    182. return true;
    183. }
    To copy to clipboard, switch view to plain text mode 

    I appreciate your help. Thank you!

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.