From 10:00 CET Friday 22nd November we will adjust how the server works to deal with some recently reported problems. Therefore there may be a load problem, if you experience more problems than usual trying to access the forum then please PM AndyS or any of the moderators so they can inform me.


QTreeView, QAbstractItemModel and internal move



  • Hi everyone,

    I try to implement an internal move of items within a QTreeView with the mouse.

    My model inherits from QAbstractItemModel with 2 columns. Each items of my model have a boolean, a name, the pointer to the parent and list of children. In the future, I intend to add other data inside my items.

    In my model, I set the flags for each valid QModelIndex to :Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;

    I implemented moveRows and moveColumns methods inside my custom Model.

    Unfortunately those methods are never called by the view.

    For information, I enable the drag and drop on the QTreeView with setDragEnable(true) and setDragDropMode(Qt::InternalMove).

    Do I need to implement all the mimeData functions just to move some data?

    I can understand the reason of mimeData for drag and drop between widgets but in my case I just want to change the parent. I don't find any documentation/example that explains type of drag and drop move.

    Thanks

    Edit: I forgot to mention my environment: Windows 10/Mac OS X High Sierra, Qt 5.10.1, Visual studio 17, Clang



  • Hi,

    I think you need to implement dropMineData in the model too.
    And call moveRow in it.


  • Moderators

    @Athius
    moveRows() and moveColumns() are not called by QAbstractItemModel. Honestly i do not know what they are used for.

    Nevertheless the item view calls dropMimeData() on the model. The default implementation then calls decodeData().
    Check the implementation of decodeData() to see what functions are called. Those are the ones you need to reimplement (like insertRows(), ...). Then setData() is called on them. So by default the moving is "faked".



  • Thanks for your answers.

    @mpergand I try to call moveRow in it but there is no change. Worse: my data are not shown anymore ^^

    @raven-worx I also try to use the default implementation of dropMimeData but when the moved item has some children, then only the item is shown without his children (the data are not corrupted, only the view).

    I already re-implement insertRows but it didn't work.

    I finally succeed by using QStandardItemModel and a custom Item that inherits from QStandardItem. There is some methods to re-implement: QStandardItem *clone() const; void read(QDataStream &in); void write(QDataStream &out) const;

    I found on the Internet a pretty convenient way to put some custom data as pointer inside a QDataStream:

    QDataStream & operator << (QDataStream & s, const Data *& data)
    {
    	qulonglong ptrval(*reinterpret_cast<qulonglong *>(&data));
    	return s << ptrval;
    }
    QDataStream & operator >> (QDataStream & s, Data & data)
    {
    	qulonglong ptrval;
    	s >> ptrval;
    	data = **reinterpret_cast<Data **>(&ptrval);
    	return s;
    }
    

    I don't know if it's the best way but it's working.



  • @Athius
    Sure it works, here my code for a bookmark tree:

    bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
    { Q_UNUSED(column)
    	if(action EQ Qt::IgnoreAction) return false;
    
             if(action EQ Qt::MoveAction)
                        {
                        QByteArray bytes=data->data(MIME_Bookmark);
                        QDataStream stream(&bytes,QIODevice::QIODevice::ReadOnly);
                        qintptr i; int r,c; 
                        stream>>i>>r>>c;
                        QModelIndex index=createIndex(r,c,i);
    
                        moveRow(index,index.row(),parent,row);
                        }
    	return true;
    	}
    

    Of course you need to create and return your custom data in mimeData () as well.