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. Qt View, QAbstractItemModel and Qt::MoveAction
QtWS25 Last Chance

Qt View, QAbstractItemModel and Qt::MoveAction

Scheduled Pinned Locked Moved General and Desktop
9 Posts 4 Posters 5.2k 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.
  • B Offline
    B Offline
    ByteWight
    wrote on last edited by
    #1

    Hello, I am using a QTreeView and an inherited QAbstractItemModel that supports only Qt::MoveAction. My problem is that when I attempt to move something, it doesn't really "move". What ends up happening is that I see that removeRows gets called and this is not good, because all of the children of the "moved" object aren't transferred.

    Therefore, my question is if it possible to make moveRows get called instead. I can't call it manually, as I don't know which object is being moved where (as mimeData and dropMimeData hold that information but execute separately). I've also tried to store the items that get modified but the compiler doesn't let me store const variables.

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to DevNet,

      Do you want to do internal moves or moving from one widget to another ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • B Offline
        B Offline
        ByteWight
        wrote on last edited by
        #3

        I'm speaking about internal moves in this case. It works so far, but not when I move an item that has children, as the children are deleted. I don't want the original item to get removed, just moved. Is this not possible within a QAbstractItemModel?

        It seems as if removeRows is called no matter what. I want it to call moveRows if I'm moving an item instead.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Since you have a custom model, it would be a good idea to share your code so it can be analyzed to see what can go wrong. i.e. did you set the view to only do internal moves ? Did you use beginMoveRows/Colums and endMoveRows/Colums etc...

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • B Offline
            B Offline
            ByteWight
            wrote on last edited by
            #5

            My TreeView Creation:
            @QTreeView view;
            view.setModel(&model);
            view.setWindowTitle("Simple Tree Model");
            view.setAcceptDrops(true);
            view.setDragEnabled(true);
            view.setDropIndicatorShown(true);
            view.setDragDropOverwriteMode(false);
            view.setDefaultDropAction(Qt::MoveAction);
            view.setDragDropMode(QTreeView::InternalMove);
            view.show();@

            And in my simple model, I have:
            @Qt::DropActions TreeModel::supportedDropActions() const
            {
            return Qt::MoveAction;
            }

            QStringList TreeModel::mimeTypes() const
            {
            return QString("text/uri-list|Item|text/plain").split("|");
            }

            QMimeData* TreeModel::mimeData(const QModelIndexList &indexes) const
            {
            if (indexes.size() != 1)
            {
            return NULL;
            }
            QMimeData* mimedata = new QMimeData();
            mimedata->setData("Item", "The data.");
            return mimedata;
            }

            bool TreeModel::dropMimeData(const QMimeData data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
            {
            if (!parent.isValid())
            {
            qDebug() << "Dropping into the root is disabled.";
            return false;
            }
            else
            {
            qDebug() << "Dropping into" << static_cast<TreeItem
            >(parent.internalPointer())->data();
            // I have to do the insert here but don't want to remove and insert. I want to move.
            }
            return true;
            }

            bool TreeModel::removeRows(int row, int count, const QModelIndex &parent)
            {
            qDebug() << "Removed.";
            return true;
            }

            bool TreeModel::insertRows(int row, int count, const QModelIndex &parent)
            {
            qDebug() << "Inserted.";
            return true;
            }

            bool TreeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
            {
            qDebug() << "Moved.";
            return true;
            }@

            I built this off of the simple tree model example. Even though my tree only supports moving, it still shows "Removed" after I move something.

            I could attempt to make a minimal example showing the problem if requested.

            1 Reply Last reply
            0
            • B Offline
              B Offline
              ByteWight
              wrote on last edited by
              #6

              I made a single source code to show the problem (divided into 2 posts, because it's long). The application should call moveRows not removeRows/insertRows, since MoveAction is the default action:

              @#include <QList>
              #include <QVariant>
              #include <QAbstractItemModel>
              #include <QModelIndex>
              #include <QStringList>
              #include <QVariant>
              #include <QMimeData>
              #include <QDebug>
              #include <QtWidgets>

              class TreeItem
              {
              public:
              TreeItem(const QList<QVariant> &data, TreeItem *parent = 0);
              ~TreeItem();

              void appendChild(TreeItem *child);
              
              TreeItem *child(int row);
              int childCount() const;
              int columnCount() const;
              QVariant data(int column) const;
              int row() const;
              TreeItem *parent();
              

              private:
              QList<TreeItem*> childItems;
              QList<QVariant> itemData;
              TreeItem *parentItem;
              };

              TreeItem::TreeItem(const QList<QVariant> &data, TreeItem *parent)
              {
              parentItem = parent;
              itemData = data;
              }

              TreeItem::~TreeItem()
              {
              qDeleteAll(childItems);
              }

              void TreeItem::appendChild(TreeItem *item)
              {
              childItems.append(item);
              }

              TreeItem *TreeItem::child(int row)
              {
              return childItems.value(row);
              }

              int TreeItem::childCount() const
              {
              return childItems.count();
              }

              int TreeItem::columnCount() const
              {
              return itemData.count();
              }

              QVariant TreeItem::data(int column) const
              {
              return itemData.value(column);
              }

              TreeItem *TreeItem::parent()
              {
              return parentItem;
              }

              int TreeItem::row() const
              {
              if (parentItem)
              return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));

              return 0;
              

              }

              class TreeItem;

              class TreeModel : public QAbstractItemModel
              {
              Q_OBJECT

              public:
              TreeModel(const QString &data, QObject *parent = 0);
              ~TreeModel();

              QVariant data(const QModelIndex &index, int role) const;
              Qt::ItemFlags flags(const QModelIndex &index) const;
              QVariant headerData(int section, Qt::Orientation orientation,
                                  int role = Qt::DisplayRole) const;
              QModelIndex index(int row, int column,
                                const QModelIndex &parent = QModelIndex()) const;
              QModelIndex parent(const QModelIndex &index) const;
              int rowCount(const QModelIndex &parent = QModelIndex()) const;
              int columnCount(const QModelIndex &parent = QModelIndex()) const;
              
              QStringList mimeTypes () const;
              QMimeData* mimeData(const QModelIndexList &indexes) const;
              bool dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
              bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild);
              bool removeRows( int row, int count, const QModelIndex & parent = QModelIndex());
              bool insertRows(int row, int count, const QModelIndex &parent);
              Qt::DropActions supportedDropActions() const;
              

              private:
              TreeItem *rootItem;
              };

              TreeModel::TreeModel(const QString &data, QObject *parent) : QAbstractItemModel(parent)
              {
              QList<QVariant> rootData;
              rootData << "Title";
              rootItem = new TreeItem(rootData);
              QList<QVariant> otherData;
              otherData << "Item 2";
              rootItem->appendChild(new TreeItem(otherData, rootItem));
              otherData.replace(0, "Item 3");
              rootItem->appendChild(new TreeItem(otherData, rootItem));
              otherData.replace(0, "Item 4");
              rootItem->appendChild(new TreeItem(otherData, rootItem));
              otherData.replace(0, "Item X");
              rootItem->child(2)->appendChild(new TreeItem(otherData, rootItem->child(2)));
              otherData.replace(0, "Item A");
              rootItem->child(2)->child(0)->appendChild(new TreeItem(otherData, rootItem->child(2)->child(0)));
              }
              @

              1 Reply Last reply
              0
              • B Offline
                B Offline
                ByteWight
                wrote on last edited by
                #7

                @TreeModel::~TreeModel()
                {
                delete rootItem;
                }

                int TreeModel::columnCount(const QModelIndex &parent) const
                {
                if (parent.isValid())
                return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
                else
                return rootItem->columnCount();
                }

                QVariant TreeModel::data(const QModelIndex &index, int role) const
                {
                if (!index.isValid())
                return QVariant();

                if (role != Qt::DisplayRole)
                    return QVariant();
                
                TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
                
                return item->data(index.column());
                

                }

                Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
                {
                return Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
                }

                QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
                int role) const
                {
                if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
                return rootItem->data(section);

                return QVariant();
                

                }

                QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent)
                const
                {
                if (!hasIndex(row, column, parent))
                return QModelIndex();

                TreeItem *parentItem;
                
                if (!parent.isValid())
                    parentItem = rootItem;
                else
                    parentItem = static_cast<TreeItem*>(parent.internalPointer());
                
                TreeItem *childItem = parentItem->child(row);
                if (childItem)
                    return createIndex(row, column, childItem);
                else
                    return QModelIndex();
                

                }

                QModelIndex TreeModel::parent(const QModelIndex &index) const
                {
                if (!index.isValid())
                return QModelIndex();

                TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
                TreeItem *parentItem = childItem->parent();
                
                if (parentItem == rootItem)
                    return QModelIndex();
                
                return createIndex(parentItem->row(), 0, parentItem);
                

                }

                int TreeModel::rowCount(const QModelIndex &parent) const
                {
                TreeItem *parentItem;
                if (parent.column() > 0)
                return 0;

                if (!parent.isValid())
                    parentItem = rootItem;
                else
                    parentItem = static_cast<TreeItem*>(parent.internalPointer());
                
                return parentItem->childCount();
                

                }

                Qt::DropActions TreeModel::supportedDropActions() const
                {
                return Qt::MoveAction;
                }

                QStringList TreeModel::mimeTypes() const
                {
                return QStringList("data");
                }

                QMimeData* TreeModel::mimeData(const QModelIndexList &indexes) const
                {
                if (indexes.size() != 1)
                {
                return NULL;
                }
                QMimeData* mimedata = new QMimeData();
                mimedata->setData("data", "testing");
                return mimedata;
                }

                bool TreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
                {
                qDebug() << "Drop Confirmed";
                return true;
                }

                bool TreeModel::removeRows(int row, int count, const QModelIndex &parent)
                {
                qDebug() << "Removed.";
                return true;
                }

                bool TreeModel::insertRows(int row, int count, const QModelIndex &parent)
                {
                qDebug() << "Inserted.";
                return true;
                }

                bool TreeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
                {
                qDebug() << "Moved.";
                return true;
                }

                int main(int argc, char *argv[])
                {
                Q_INIT_RESOURCE(simpletreemodel);

                QApplication app(argc, argv);
                
                TreeModel model("Item1");
                
                QTreeView view;
                view.setModel(&model);
                view.setWindowTitle("Simple Tree Model");
                view.setAcceptDrops(true);
                view.setDragEnabled(true);
                view.setDropIndicatorShown(true);
                view.setDragDropOverwriteMode(false);
                view.setDefaultDropAction(Qt::MoveAction);
                view.setDragDropMode(QTreeView::InternalMove);
                view.show();
                
                return app.exec();
                

                }

                @

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  sizanical_bill
                  wrote on last edited by
                  #8

                  This might be a dumb observation on a somewhat stale thread. But I was looking into a similar issue and realized that the QAbstractItemModel::moveRows virtual function is new in Qt5. So If you're using an older version of Qt I guess (although I haven't actually confirmed yet) that moves are implemented in terms of a remove and an insert. In which case, the behaviour described by the OP would be expected.

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    AntonyEnergy
                    wrote on last edited by
                    #9

                    view.setDragDropOverwriteMode(true);
                    And raw will not be deleted.

                    1 Reply Last reply
                    0

                    • Login

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