Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Custom QStandardItem drag and drop not working properly
Forum Updated to NodeBB v4.3 + New Features

Custom QStandardItem drag and drop not working properly

Scheduled Pinned Locked Moved Unsolved General and Desktop
qstandarditemqstandarditemmodrag and dropqtreeview
2 Posts 2 Posters 1.8k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • YohduY Offline
    YohduY Offline
    Yohdu
    wrote on last edited by Yohdu
    #1

    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

    raven-worxR 1 Reply Last reply
    0
    • YohduY Yohdu

      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

      raven-worxR Offline
      raven-worxR Offline
      raven-worx
      Moderators
      wrote on last edited by raven-worx
      #2

      @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)

      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
      If you have a question please use the forum so others can benefit from the solution in the future

      1 Reply Last reply
      1

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved