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
QtWS25 Last Chance

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.
  • Y Offline
    Y Offline
    Yohdu
    wrote on 3 Aug 2016, 08:42 last edited by Yohdu 8 Mar 2016, 08:45
    #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

    R 1 Reply Last reply 3 Aug 2016, 13:43
    0
    • Y Yohdu
      3 Aug 2016, 08:42

      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

      R Offline
      R Offline
      raven-worx
      Moderators
      wrote on 3 Aug 2016, 13:43 last edited by raven-worx 8 Mar 2016, 13:43
      #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

      1/2

      3 Aug 2016, 08:42

      • Login

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