Results 1 to 3 of 3

Thread: Problem with QListView Drag & Drop

  1. #1
    Join Date
    Aug 2013
    Posts
    6
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Problem with QListView Drag & Drop

    hello,

    I have a problem with my QListView Drag & Drop. I am using Qt 5.1.

    I have implemented a custom object and a custom model which I use with a standard QListView (if I substitute the list view with a QTreeView the code works perfectly).

    When I set the view mode as IconMode the following happens :
    If I drag & Drop an item in my list view it just disappears. The dropMimeData is never called.
    While if I drag my item on top of another item it seems to work (i.e. the dragged item is being added as a child).
    If the item is dragged into the empty space it just disappears.

    if I set the view mode to ListMode the following happens :
    If I drag an item over another item it just disappears, while if I drag it to the end of the list , the item is added at the bottom of the list.

    so here is some code

    Qt Code:
    1. #include <QApplication>
    2. #include <QListView>
    3. #include <QTreeView>
    4.  
    5. #include "ObjectBase.h"
    6. #include "QtTreeModelBase.h"
    7.  
    8. int main(int argc, char **argv)
    9. {
    10. QApplication a(argc, argv);
    11.  
    12.  
    13. cObjectBase* pRoot = new cObjectBase(NULL);
    14. pRoot->setObjectName("Root");
    15.  
    16. for(int i = 1; i < 10; ++i)
    17. {
    18. cObjectBase* pChild = new cObjectBase(pRoot);
    19. pChild->setObjectName(QString("Item %1").arg(i));
    20. }
    21.  
    22. QTreeModelBase* pTreeModelBase = new QTreeModelBase("Objects", pRoot, NULL);
    23. pTreeModelBase->Reset(pRoot);
    24.  
    25. lw.setModel(pTreeModelBase);
    26.  
    27. lw.setDragEnabled(true);
    28. lw.viewport()->setAcceptDrops(true);
    29. lw.setDefaultDropAction(Qt::MoveAction);
    30. lw.setDropIndicatorShown(true);
    31. lw.setViewMode(QListView::ListMode);
    32. lw.setDragDropMode(QAbstractItemView::InternalMove);
    33.  
    34. lw.show();
    35.  
    36. a.exec();
    37. }
    To copy to clipboard, switch view to plain text mode 

    and here my object

    Qt Code:
    1. #ifndef OBJECT_BASE_H
    2. #define OBJECT_BASE_H
    3.  
    4. #include <QObject>
    5. #include <QString>
    6.  
    7. #include <QtCore/QXmlStreamReader>
    8. #include <QtCore/QXmlStreamWriter>
    9.  
    10. #include <QAbstractitemview>
    11.  
    12. class cObjectBase : public QObject
    13. {
    14. Q_OBJECT
    15. public:
    16. cObjectBase(cObjectBase* pParent);
    17. virtual ~cObjectBase();
    18.  
    19. static const QString ObjectTag;
    20.  
    21. virtual void SetParent(cObjectBase* pParent, bool bConsiderChildren);
    22. cObjectBase* GetParent()const;
    23. void AddChild(cObjectBase* pChild);
    24. void InsertChild(int row, cObjectBase *pChild);
    25. void SwapChildren(int oldRow, int newRow);
    26. cObjectBase* TakeChild(int row);
    27. cObjectBase* TakeChild(cObjectBase* pChild);
    28. int RowOfChild(cObjectBase* pChild) const;
    29. int ChildCount(bool bIgnoreManager) const;
    30. cObjectBase* ChildAt(int row) const;
    31. void RemoveAllChildren(); //will not delete children
    32.  
    33. void WriteToXML(QXmlStreamWriter* pWriter, bool bSkipChildren, bool bDragDrop)const;
    34. virtual void WriteAttributesToXML(QXmlStreamWriter* pWriter, bool bDragDrop)const;
    35.  
    36. void ReadFromXML(QXmlStreamReader* pReader, const QString& parentPath, bool bSkipChildren = false);
    37. virtual void ReadAttributesFromXML(QXmlStreamReader* pReader, bool bDragDrop);
    38.  
    39. protected:
    40. static const QString NameTag;
    41.  
    42. cObjectBase* mpParent;
    43. QList<cObjectBase*> mChildren;
    44. };
    45.  
    46. #endif
    To copy to clipboard, switch view to plain text mode 

    implemented as

    Qt Code:
    1. #include "ObjectBase.h"
    2. #include "QtTreeModelBase.h"
    3.  
    4.  
    5. const QString cObjectBase::ObjectTag("Object");
    6.  
    7.  
    8. cObjectBase::cObjectBase(cObjectBase* pParent) :
    9. QObject(NULL), //not setting parents on purpose here
    10. mpParent(pParent)
    11. {
    12. setObjectName("New Object");
    13. if(pParent)
    14. {
    15. pParent->AddChild(this);
    16. }
    17. }
    18.  
    19. cObjectBase::~cObjectBase()
    20. {
    21. qDeleteAll(mChildren);
    22. }
    23.  
    24. void cObjectBase::SetParent(cObjectBase* pParent, bool bConsiderChildren)
    25. {
    26. if(bConsiderChildren)
    27. {
    28. if(mpParent)
    29. {
    30. if(mpParent != pParent)
    31. {
    32. mpParent->TakeChild(this);
    33. }
    34. }
    35.  
    36. if(pParent)
    37. {
    38. pParent->AddChild(this);
    39. }
    40. }
    41.  
    42. mpParent = pParent;
    43. }
    44.  
    45. cObjectBase* cObjectBase::GetParent()const
    46. {
    47. return mpParent;
    48. }
    49.  
    50. cObjectBase* cObjectBase::TakeChild(int row)
    51. {
    52. cObjectBase* pItem = mChildren.takeAt(row);
    53. Q_ASSERT(pItem);
    54. pItem->mpParent = 0;
    55. return pItem;
    56. }
    57.  
    58. cObjectBase* cObjectBase::TakeChild(cObjectBase* pChild)
    59. {
    60. for (unsigned int row = 0; row < mChildren.count(); ++row)
    61. {
    62. cObjectBase* pMyChild = mChildren.at(row);
    63.  
    64. if(pMyChild == pChild)
    65. {
    66. return TakeChild(row);
    67. }
    68. }
    69.  
    70. return NULL;
    71. }
    72.  
    73. void cObjectBase::InsertChild(int row, cObjectBase* pChild)
    74. {
    75. pChild->mpParent = this;
    76. mChildren.insert(row, pChild);
    77. }
    78.  
    79. void cObjectBase::AddChild(cObjectBase* pItem)
    80. {
    81. pItem->SetParent(this, false);
    82. mChildren << pItem;
    83. }
    84.  
    85. void cObjectBase::SwapChildren(int oldRow, int newRow)
    86. {
    87. mChildren.swap(oldRow, newRow);
    88. }
    89.  
    90. int cObjectBase::RowOfChild(cObjectBase* pChild) const
    91. {
    92. return mChildren.indexOf(pChild);
    93. }
    94.  
    95. int cObjectBase::ChildCount(bool bIgnoreManager) const
    96. {
    97. return mChildren.count();
    98. }
    99.  
    100. cObjectBase* cObjectBase::ChildAt(int row) const
    101. {
    102. return mChildren.value(row);
    103. }
    104.  
    105. void cObjectBase::RemoveAllChildren()
    106. {
    107. mChildren.clear();
    108. }
    109.  
    110. const QString cObjectBase::NameTag("Name");
    111.  
    112. void cObjectBase::WriteToXML(QXmlStreamWriter* pWriter, bool bSkipChildren, bool bDragDrop) const
    113. {
    114. pWriter->writeStartElement(ObjectTag);
    115.  
    116. WriteAttributesToXML(pWriter, bDragDrop);
    117.  
    118. foreach(cObjectBase* pChild, mChildren)
    119. {
    120. pChild->WriteToXML(pWriter, bSkipChildren, bDragDrop);
    121. }
    122.  
    123. pWriter->writeEndElement(); //end "Object"
    124. }
    125.  
    126. void cObjectBase::WriteAttributesToXML(QXmlStreamWriter* pWriter, bool bDragDrop)const
    127. {
    128. pWriter->writeAttribute(NameTag, objectName());
    129. }
    130.  
    131. void cObjectBase::ReadAttributesFromXML(QXmlStreamReader* pReader, bool bDragDrop)
    132. {
    133. QString name = pReader->attributes().value(NameTag).toString();
    134. setObjectName(name);
    135. }
    To copy to clipboard, switch view to plain text mode 

    and now the model

    Qt Code:
    1. #ifndef QTREEMODELBASE_H
    2. #define QTREEMODELBASE_H
    3.  
    4. #include <QAbstractItemModel>
    5.  
    6. #include <QtCore/QXmlStreamReader>
    7. #include <QtCore/QXmlStreamWriter>
    8.  
    9. class QMimeData;
    10. class cObjectBase;
    11.  
    12. class QTreeModelBase : public QAbstractItemModel
    13. {
    14. Q_OBJECT
    15.  
    16. public:
    17. QTreeModelBase(QString columnName, cObjectBase *root, QObject *parent = 0 );
    18.  
    19. void ResetRoot(cObjectBase* root);
    20. cObjectBase* GetRoot()const { return mpRootItem; }
    21.  
    22. virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
    23. virtual QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const;
    24.  
    25. QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
    26.  
    27. int rowCount( const QModelIndex &parent = QModelIndex() ) const;
    28. virtual int columnCount( const QModelIndex &parent = QModelIndex() ) const;
    29.  
    30. QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const;
    31. virtual QModelIndex parent( const QModelIndex &index ) const;
    32.  
    33. cObjectBase* GetBaseObject(const QModelIndex& index ) const;
    34.  
    35. bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex());
    36.  
    37. QModelIndex GetObjectIndex(cObjectBase* pObjectBase, const QModelIndex& parent);
    38. QModelIndex GetObjectIndex(cObjectBase* pObjectBase);
    39.  
    40. void Reset(cObjectBase* pObjectBase);
    41.  
    42. Qt::DropActions supportedDragActions() const { return Qt::MoveAction; }
    43. Qt::DropActions supportedDropActions() const { return Qt::MoveAction; }
    44.  
    45. QStringList mimeTypes() const;
    46. QMimeData *mimeData(const QModelIndexList &indexes) const;
    47. bool dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &parent);
    48.  
    49. protected:
    50. QString mColumnName;
    51. cObjectBase *mpRootItem;
    52.  
    53. private:
    54. void WriteObjectAndChildren(QXmlStreamWriter *writer, cObjectBase* pItem) const;
    55. bool ReadObjects(QXmlStreamReader* pReader, cObjectBase* pItem);
    56. };
    57.  
    58. #endif // OBJECTTREEMODEL_H
    To copy to clipboard, switch view to plain text mode 

    implemented as

    Qt Code:
    1. #include <QMetaObject>
    2. #include <QMimeData>
    3.  
    4. #include "QtTreeModelBase.h"
    5. #include "ObjectBase.h"
    6.  
    7. const QString MimeType = "cObjectBase.xml";
    8.  
    9. QTreeModelBase::QTreeModelBase(QString columnName, cObjectBase *root, QObject *parent ) :
    10. {
    11. mColumnName = columnName;
    12. mpRootItem = root;
    13. }
    14.  
    15. void QTreeModelBase::ResetRoot(cObjectBase* root)
    16. {
    17. mpRootItem = root;
    18. }
    19.  
    20. Qt::ItemFlags QTreeModelBase::flags(const QModelIndex &index) const
    21. {
    22. return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable;
    23. }
    24.  
    25. QVariant QTreeModelBase::data( const QModelIndex &index, int role) const
    26. {
    27. if( !index.isValid() )
    28. return QVariant();
    29.  
    30. cObjectBase* pItem = GetBaseObject(index);
    31.  
    32. if(!pItem)
    33. {
    34. return QVariant();
    35. }
    36.  
    37. if( role == Qt::DisplayRole )
    38. {
    39. switch( index.column() )
    40. {
    41. case 0:
    42. {
    43. QString name = pItem->objectName();
    44. return name;
    45. }
    46. break;
    47. default:
    48. break;
    49. }
    50. }
    51.  
    52. return QVariant();
    53. }
    54.  
    55. QVariant QTreeModelBase::headerData(int section, Qt::Orientation orientation, int role ) const
    56. {
    57. if( role != Qt::DisplayRole || orientation != Qt::Horizontal )
    58. return QVariant();
    59.  
    60. switch( section )
    61. {
    62. case 0:
    63. return mColumnName;
    64. default:
    65. return QVariant();
    66. }
    67. }
    68.  
    69. int QTreeModelBase::rowCount(const QModelIndex &parent ) const
    70. {
    71. if (parent.isValid() && parent.column() != 0)
    72. return 0;
    73.  
    74. cObjectBase* pParentItem = GetBaseObject(parent);
    75. return pParentItem ? pParentItem->ChildCount(false) : 0;
    76. }
    77.  
    78. int QTreeModelBase::columnCount(const QModelIndex &parent ) const
    79. {
    80. return 1; //parent.isValid() ? 1 : 0;
    81. }
    82.  
    83. QModelIndex QTreeModelBase::index(int row, int column, const QModelIndex &parent ) const
    84. {
    85. if (!mpRootItem || row < 0 || column < 0 || column >= 1 || (parent.isValid() && parent.column() != 0))
    86. return QModelIndex();
    87.  
    88. cObjectBase* pParentItem = GetBaseObject(parent);
    89. Q_ASSERT(pParentItem);
    90.  
    91. cObjectBase* pItem = pParentItem->ChildAt(row);
    92. if(pItem)
    93. {
    94. QModelIndex index = createIndex(row, column, pItem);
    95. return index;
    96. }
    97.  
    98. return QModelIndex();
    99. }
    100.  
    101. QModelIndex QTreeModelBase::parent(const QModelIndex &index) const
    102. {
    103. if( !index.isValid() )
    104. return QModelIndex();
    105.  
    106. cObjectBase* pChildItem = GetBaseObject(index);
    107. if(pChildItem)
    108. {
    109. cObjectBase* pParentItem = static_cast<cObjectBase*>(pChildItem->GetParent());
    110. if(pParentItem)
    111. {
    112. if(pParentItem == mpRootItem)
    113. {
    114. return QModelIndex();
    115. }
    116.  
    117. cObjectBase* pGrandParentItem = static_cast<cObjectBase*>(pParentItem->GetParent());
    118. if(pGrandParentItem)
    119. {
    120. int row = pGrandParentItem->RowOfChild(pParentItem);
    121. return createIndex(row, 0, pParentItem);
    122. }
    123. }
    124. }
    125.  
    126. return QModelIndex();
    127. }
    128.  
    129. cObjectBase* QTreeModelBase::GetBaseObject(const QModelIndex& index ) const
    130. {
    131. if( !index.isValid() )
    132. {
    133. return mpRootItem;
    134. }
    135.  
    136. return static_cast<cObjectBase*>( index.internalPointer() );
    137. }
    138.  
    139. bool QTreeModelBase::removeRows(int row, int count, const QModelIndex &parent)
    140. {
    141. if(!mpRootItem)
    142. {
    143. return false;
    144. }
    145.  
    146. cObjectBase* pItem = parent.isValid() ? GetBaseObject(parent) : mpRootItem;
    147. beginRemoveRows(parent, row, row + count - 1);
    148. for (int i = 0; i < count; ++i)
    149. {
    150. /*delete */pItem->TakeChild(row);
    151. }
    152. endRemoveRows();
    153. layoutChanged();
    154. return true;
    155. }
    156.  
    157. QModelIndex QTreeModelBase::GetObjectIndex(cObjectBase* pObjectBase, const QModelIndex& parent)
    158. {
    159. int myRowCount = rowCount(parent);
    160.  
    161. for(int row = 0; row < myRowCount; ++row)
    162. {
    163. QModelIndex i = index(row, 0, parent);
    164.  
    165. if(i.isValid())
    166. {
    167. cObjectBase* pObject = GetBaseObject(i);
    168. if(pObject == pObjectBase)
    169. {
    170. return i;
    171. }
    172.  
    173. QModelIndex r = GetObjectIndex(pObjectBase, i);
    174. if(r.isValid())
    175. {
    176. cObjectBase* pObj = GetBaseObject(i);
    177. if(pObj == pObjectBase)
    178. {
    179. return r;
    180. }
    181. }
    182. }
    183. }
    184.  
    185. return QModelIndex();
    186. }
    187.  
    188. QModelIndex QTreeModelBase::GetObjectIndex(cObjectBase* pObjectBase)
    189. {
    190. cObjectBase* pParentObject = pObjectBase->GetParent();
    191.  
    192. QList<cObjectBase*> parentsList;
    193.  
    194. while(pParentObject && pParentObject != mpRootItem)
    195. {
    196. parentsList.push_front(pParentObject);
    197.  
    198. pParentObject = pParentObject->GetParent();
    199. }
    200.  
    201. QModelIndex parentIndex = QModelIndex();
    202.  
    203. if(!parentsList.isEmpty())
    204. {
    205. cObjectBase* pCurrentItem = (*parentsList.begin());
    206. parentsList.pop_front();
    207. parentIndex = GetObjectIndex(pCurrentItem, parentIndex);
    208.  
    209. while(pCurrentItem && !parentsList.isEmpty())
    210. {
    211. pCurrentItem = (*parentsList.begin());
    212. parentsList.pop_front();
    213. parentIndex = GetObjectIndex(pCurrentItem, parentIndex);
    214. }
    215. }
    216.  
    217. QModelIndex returnIndex = parentIndex;
    218.  
    219. return returnIndex;
    220. }
    221.  
    222. void QTreeModelBase::Reset(cObjectBase* pObjectBase)
    223. {
    224. beginResetModel();
    225. ResetRoot(pObjectBase);
    226. endResetModel();
    227. }
    228.  
    229.  
    230. QStringList QTreeModelBase::mimeTypes() const
    231. {
    232. return QStringList() << MimeType;
    233. }
    234.  
    235.  
    236. QMimeData* QTreeModelBase::mimeData(const QModelIndexList &indexes) const
    237. {
    238. Q_ASSERT(indexes.count());
    239. if (indexes.count() != 1)
    240. {
    241. return NULL;
    242. }
    243.  
    244. cObjectBase* pItem = GetBaseObject(indexes.at(0));
    245.  
    246. if(pItem)
    247. {
    248. QMimeData* pMimeData = new QMimeData;
    249. QByteArray xmlData;
    250. QXmlStreamWriter writer(&xmlData);
    251. WriteObjectAndChildren(&writer, pItem);
    252. static const int MaxCompression = 9;
    253. pMimeData->setData(MimeType, qCompress(xmlData, MaxCompression));
    254. return pMimeData;
    255. }
    256.  
    257. return NULL;
    258. }
    259.  
    260.  
    261. bool QTreeModelBase::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &parent)
    262. {
    263. if (action == Qt::IgnoreAction)
    264. return true;
    265.  
    266. if (action != Qt::MoveAction || column > 0 || !mimeData || !mimeData->hasFormat(MimeType))
    267. return false;
    268.  
    269. cObjectBase* pItem = GetBaseObject(parent);
    270.  
    271. if(pItem)
    272. {
    273. QByteArray xmlData = qUncompress(mimeData->data(MimeType));
    274. QXmlStreamReader reader(xmlData);
    275. if (row == -1)
    276. {
    277. row = parent.isValid() ? parent.row() : mpRootItem->ChildCount(true);
    278. }
    279. beginInsertRows(parent, row, row);
    280. bool bDropped = ReadObjects(&reader, pItem);
    281. endInsertRows();
    282. return bDropped;
    283. }
    284. return false;
    285. }
    286.  
    287. void QTreeModelBase::WriteObjectAndChildren(QXmlStreamWriter* pWriter, cObjectBase* pItem) const
    288. {
    289. if(pItem != mpRootItem)
    290. {
    291. pItem->WriteToXML(pWriter, false, true);
    292. }
    293. }
    294.  
    295. bool QTreeModelBase::ReadObjects(QXmlStreamReader* pReader, cObjectBase* pItem)
    296. {
    297. while(!pReader->atEnd())
    298. {
    299. pReader->readNext();
    300. if(pReader->isStartElement())
    301. {
    302. if(pReader->name() == cObjectBase::ObjectTag)
    303. {
    304. cObjectBase* pNewObject = new cObjectBase(NULL);
    305. pNewObject->ReadAttributesFromXML(pReader, true);
    306.  
    307. pItem->AddChild(pNewObject);
    308. pItem = pNewObject;
    309. }
    310. }
    311. else if(pReader->isEndElement())
    312. {
    313. if(pReader->name() == cObjectBase::ObjectTag)
    314. {
    315. Q_ASSERT(pItem);
    316. pItem = pItem->GetParent();
    317. Q_ASSERT(pItem);
    318. }
    319. }
    320. }
    321. return true;
    322. }
    To copy to clipboard, switch view to plain text mode 

    can anyone see why I have got the drag and drop bug ?
    I saw that apparently there was a bug in an earlier version of Qt that sounds very similar but it is claimed fixed.

    https://bugreports.qt-project.org/browse/QTBUG-31061

  2. #2
    Join Date
    Aug 2013
    Posts
    6
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Problem with QListView Drag & Drop

    it appears that also this bug was reported and closed and it sounds very similar to my problem... maybe there is still a Qt bug with QListView drag & drop

    https://bugreports.qt-project.org/br...mment-tabpanel

  3. #3
    Join Date
    Aug 2013
    Posts
    6
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Problem with QListView Drag & Drop

    should I report this as a Qt bug ? or has really nobody here ever implemented a custom model to be used with QListView and drag and drop ?

Similar Threads

  1. qt 3.3 qlistview drag and drop
    By harishiva in forum Qt Programming
    Replies: 0
    Last Post: 21st September 2011, 12:46
  2. Replies: 2
    Last Post: 13th October 2010, 21:51
  3. Drag and Drop from QListView to QGraphicsView
    By NoRulez in forum Qt Programming
    Replies: 0
    Last Post: 20th August 2009, 14:26
  4. qlistview drag&drop problem
    By moowy in forum Qt Programming
    Replies: 8
    Last Post: 13th October 2006, 14:49
  5. Problem with drag&drop in qlistview
    By mambo in forum Qt Programming
    Replies: 2
    Last Post: 11th September 2006, 16:14

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.