Results 1 to 2 of 2

Thread: QListView/QAbstractItemView and list internal drag & drop

  1. #1
    Join Date
    Oct 2012
    Posts
    132
    Thanks
    10
    Thanked 21 Times in 21 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Question QListView/QAbstractItemView and list internal drag & drop

    Hi,

    I have a QListView which shows data from a custom model which is based on QAbstractListModel.

    Now I want that the user can reorder the items via drag & drop. To achive that I set movment to Snap, dragAndDropMode to InternalMove and defaultDropAction to Move.

    I also reimplemented some methods of the model to enable drag and drop funcationality (see the code above).

    There are two problems:
    - When moving an item via drag & drop it gets inserted properly at the new position (and the data is properly set as well), but the old item at the old position gets not removed properly. removeRow() is called, but row is according to the debugger and the result I see always 2. Has anybody an idea why where this problem comes from?

    - It is possible to drop an item over another item. This works. The old item gets removed and the data of the "target item" is set correctly. But I don't want that behaviour. I want to disable the possibility of droping an item over another item. I just want the possiblity to reorder the items.

    Here is my code. I added some comments.

    Qt Code:
    1. QVariant FieldModel::data(const QModelIndex &index, int role) const
    2. {
    3. if(index.isValid() && index.row() < m_fields.size()) {
    4. switch(role) {
    5. case Qt::DisplayRole:
    6. return fieldName(m_fields.at(index.row()).first);
    7. case Qt::CheckStateRole:
    8. return m_fields.at(index.row()).second ? Qt::Checked : Qt::Unchecked;
    9. case fieldRole:
    10. return m_fields.at(index.row()).first;
    11. default:
    12. ;
    13. }
    14. }
    15. return QVariant();
    16. }
    17.  
    18. bool FieldModel::setData(const QModelIndex &index, const QVariant &value, int role)
    19. {
    20. bool success = false;
    21. if(index.isValid() && index.row() < m_fields.size()) {
    22. switch(role) {
    23. case Qt::CheckStateRole:
    24. if(value.canConvert(QMetaType::Int)) {
    25. m_fields[index.row()].second = value.toInt() == Qt::Checked;
    26. success = true;
    27. }
    28. break;
    29. case fieldRole:
    30. if(value.canConvert(QMetaType::Int)) {
    31. m_fields[index.row()].first = value.toInt();
    32. success = true;
    33. }
    34. break;
    35. default:
    36. ;
    37. }
    38. }
    39. if(success) {
    40. dataChanged(index, index, QVector<int>() << role);
    41. }
    42. return success;
    43. }
    44.  
    45. // I'm using an user role. I reimplemented itemData to return data for that role as well.
    46. QMap<int, QVariant> FieldModel::itemData(const QModelIndex &index) const
    47. {
    48. QMap<int, QVariant> roles;
    49. for (int i = 0; i <= fieldRole; ++i) {
    50. QVariant variantData = data(index, i);
    51. if (variantData.isValid())
    52. roles.insert(i, variantData);
    53. }
    54. return roles;
    55. }
    56.  
    57. bool FieldModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
    58. {
    59. for (QMap<int, QVariant>::ConstIterator it = roles.constBegin(); it != roles.constEnd(); ++it)
    60. setData(index, it.value(), it.key());
    61. return true;
    62. // the default implementation (from qabstractitemmodel.cpp)
    63. // bool b = true;
    64. // for (QMap<int, QVariant>::ConstIterator it = roles.begin(); it != roles.end(); ++it)
    65. // b = b && setData(index, it.value(), it.key()); // does not call setData() after setData() returned once false -> thats why I reimplemented the method
    66. // return b;
    67. }
    68.  
    69. Qt::DropActions FieldModel::supportedDropActions() const
    70. {
    71. return Qt::MoveAction;
    72. }
    73.  
    74. Qt::DropActions FieldModel::supportedDragActions() const
    75. {
    76. return Qt::MoveAction;
    77. }
    78.  
    79. bool FieldModel::insertRows(int row, int count, const QModelIndex &parent)
    80. {
    81. if(parent.isValid())
    82. return false;
    83.  
    84. beginInsertRows(parent, row, 0);
    85. for(int index = row, end = row + count; index < end; ++index) {
    86. m_fields.insert(index, p(KnownField::Invalid, false));
    87. }
    88. endInsertRows();
    89. return true;
    90. }
    91.  
    92. // since the model has only one column is don't think I need to do here more
    93. bool FieldModel::insertColumns(int , int , const QModelIndex &)
    94. {
    95. return false;
    96. }
    97.  
    98. bool FieldModel::removeRows(int row, int count, const QModelIndex &parent)
    99. {
    100. // row is always 2 when this method is called
    101. if(parent.isValid())
    102. return false;
    103.  
    104. if(count) {
    105. beginRemoveRows(parent, row, row + count - 1);
    106. for(int index = row, end = row + count; index < end; ++index) {
    107. m_fields.removeAt(index);
    108. }
    109. endRemoveRows();
    110. }
    111. return true;
    112. }
    113.  
    114. // since the model has only one column is don't think I need to do here more
    115. bool FieldModel::removeColumns(int , int , const QModelIndex &)
    116. {
    117. return false;
    118. }
    To copy to clipboard, switch view to plain text mode 

    Thanks for helping.

  2. #2
    Join Date
    Oct 2012
    Posts
    132
    Thanks
    10
    Thanked 21 Times in 21 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Lightbulb Re: QListView/QAbstractItemView and list internal drag & drop

    I solved the second problem. To allow drops only outside the items and not over the items I use the following flags reimplementation in my model:
    Qt Code:
    1. Qt::ItemFlags FieldModel::flags(const QModelIndex &index) const
    2. {
    3. if (!index.isValid() || index.row() >= m_fields.count() || index.model() != this)
    4. return Qt::ItemIsDropEnabled; // we allow drops outside the items
    5. return QAbstractListModel::flags(index) | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
    6. }
    To copy to clipboard, switch view to plain text mode 
    This solution is taken from qtbase/src/widgets/qlistwidget.cpp.

    Edit: I also solved the first problem. These are the correct reimplementations of insertRows and removeRows in my case:
    Qt Code:
    1. bool FieldModel::insertRows(int row, int count, const QModelIndex &parent)
    2. {
    3. if (count < 1 || row < 0 || row > rowCount() || parent.isValid())
    4. return false;
    5. beginInsertRows(QModelIndex(), row, row + count - 1);
    6. for(int index = row, end = row + count; index < end; ++index)
    7. m_fields.insert(index, p(KnownField::Invalid, false));
    8. endInsertRows();
    9. return true;
    10. }
    11.  
    12. bool FieldModel::removeRows(int row, int count, const QModelIndex &parent)
    13. {
    14. if (count < 1 || row < 0 || (row + count) > rowCount() || parent.isValid())
    15. return false;
    16. beginRemoveRows(QModelIndex(), row, row + count - 1);
    17. for(int index = row, end = row + count; index < end; ++index)
    18. m_fields.removeAt(index);
    19. endRemoveRows();
    20. return true;
    21. }
    To copy to clipboard, switch view to plain text mode 
    The problem was caused here: beginInsertRows(parent, row, 0);
    The third argument has to be row + count - 1.
    Last edited by Infinity; 15th June 2014 at 21:37.

Similar Threads

  1. QTableWidget Internal Drag/ Drop Entire Row
    By davethomaspilot in forum Newbie
    Replies: 0
    Last Post: 16th December 2012, 01:31
  2. Replies: 1
    Last Post: 6th April 2011, 08:24
  3. Replies: 2
    Last Post: 13th October 2010, 22:51
  4. Drag drop internal
    By valgaba in forum Qt Programming
    Replies: 0
    Last Post: 30th September 2010, 15:49
  5. QAbstractItemView drag & drop bug or feature?
    By wysota in forum Qt Programming
    Replies: 0
    Last Post: 13th September 2010, 23:42

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
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.