Custom QStandardItem drag and drop not working properly
-
Hello,
I come to you cause I do not manage to make my custom QStandardItem/QStandardItemModel working as I want it to.
I basically have these 4 classes :
class Map { public: Map(); Map(const sf::String& name); Map(const Map& map); //accessor private: sf::String m_name; }; /*****************************************/ class MapItem : public QStandardItem { public: MapItem(Map* map); Map* map() const; QVariant data(int role = Qt::UserRole + 1) const; void setData(const QVariant &value, int role = Qt::UserRole + 1); QStandardItem* clone() const; private: Map* m_map; }; /*****************************************/ class MapItemModel : public QStandardItemModel { public: MapItemModel(); }; /*****************************************/ class MapItemView : public QTreeView { public: MapItemView(QWidget* parent = Q_NULLPTR); QSize sizeHint() const; };
So there is a custom QStandardItem (MapItem) which contains a pointer on a Map object. My first question is : is it the correct way to have a QStandardItem containing custom data ? Or should I use the setData method with a custom userRole (which I tried but did not seem to be really pertinent in my opinion) ?
Then, I have a custom model which I aliment with MapItems. My model is set in an MapItemView, which is simply a QTreeView in which I intend to implement custom behaviors. My second and main problem is that I cannot manage to make internal move operations work properly. Here is the relevant source code:
//***********MapItem MapItem::MapItem(Map* map) { m_map = map; } Map* MapItem::map() const { return m_map; } QVariant MapItem::data(int role) const { if(role == Qt::DisplayRole || role == Qt::EditRole) { return QVariant(map()->name().toAnsiString().c_str()); } return QStandardItem::data(role); } void MapItem::setData(const QVariant &value, int role) { if(role == Qt::DisplayRole || role == Qt::EditRole) { QString mapName = value.toString(); map()->setName(mapName.toStdString().c_str()); emitDataChanged(); } else { QStandardItem::setData(value, role); } } QStandardItem* MapItem::clone() const { Map* map = new Map(*m_map); MapItem* mapItem = new MapItem(map); return mapItem; } //***********MapItemModel MapItemModel::MapItemModel() : QStandardItemModel() { setItemPrototype(new MapItem(new Map())); QStandardItem* parentItem = invisibleRootItem(); MapItem* mapItem = new MapItem(new Map("test1")); parentItem->appendRow(mapItem); mapItem->appendRow(new MapItem(new Map("test11"))); mapItem->appendRow(new MapItem(new Map("test12"))); parentItem->appendRow(new MapItem(new Map("test2"))); parentItem->appendRow(new MapItem(new Map("test3"))); } //***********MapItemView MapItemView::MapItemView(QWidget* parent) : QTreeView(parent) { setModel(new MapItemModel); setHeaderHidden(true); expandAll(); //drag and drop setSelectionMode(QAbstractItemView::SingleSelection); setDragEnabled(true); viewport()->setAcceptDrops(true); setDropIndicatorShown(true); setDragDropMode(QAbstractItemView::InternalMove); }
When I perform a move operation of a MapItem, the MapItem i moved "dissapears" and a new default empty MapItem is provided. According to the documentation, it must be caused by the
setItemPrototype(new MapItem(new Map()));
call. But if I do not call this method, the moved MapItem "becomes" a QStandardItem (thus with no Map object).
My second and main question is then : how to implement correct drag and drop operations with custom QStandardItem which needs to own custom data ?
With thanks
-
@Yohdu said:
My second and main question is then : how to implement correct drag and drop operations with custom QStandardItem which needs to own custom data ?
With the standard item widgets/models you can't drag-n-drop custom item roles.
This makes sense, since the model doesn't know which UserRole+ was set.
It would need to iterate all possible item-role values when creating the drop-data.The only solution i see is to create your own custom model and reimplement the needed drag-n-drop methods. This also give you full control over your data structure storing the data inside the model.
This is more work, but you will learn a lot and gain some performance (by avoiding the standard-item classes)