QTreeView drop not working



  • I have two QTreeView both using custom implementations of QAbstractItemModel. I want to be able to drag an item from one QTreeView and drop it into the other QTreeView. This means that one QTreeView only supports dragging and the other one only supports dropping.
    The dragging part is working and my model successfully encodes the data as a QMimeData object and I know from another place that it works. Also, I get the proper "dragging item" animation.
    My problem starts with the dropping: I can't drop any item into the other QTreeView. When I drag an item into the view, I see the "nope, you cannot drop here" animation. However, I can see that in my model QAbstractItemModel::canDropMimeData() is being executed and I always return true. However, the corresponding QAbstractItemModel::dropMimeData() never gets called (and the animation shows that I can't drop).

    In the QTreeView I did the following two things:

    QTreeView* dropTreeView = new QTreeView;
    dropTreeView->setModel(myModel);
    dropTreeView->setDragDropMode(QAbstractItemView::DropOnly);
    dropTreeView->setAcceptDrops(true);
    

    However, no luck. The tree view keeps rejecting the drop.

    Once I got very desperate I manually subclassed QTreeView and overloaded the corresponding QTreeView::dragEnterEvent(), QTreeView::dropEvent() and so on. In those, I simply use qDebug() to output a message and then call the default implementation. This allows me to see that all the dragXxx() methods are executed but the dropEvent() never.

    I'm totally lost here. Any ideas?



  • This issue is now resolved. It turned out to be a problem in the model: I forgot to tell the root (invalid parent) to accept drops too. This is done in the QAbstractItemModel::flags() implementation.
    The incorrect version was:

    Qt::ItemFlags MyModel::flags(const QModelIndex& index) const
    {
        if (!index.isValid()) {
            return 0;
        }
    
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
    }
    

    While this is how it should look like to allow drops in the root (to add new items without a parent):

    Qt::ItemFlags MyModel::flags(const QModelIndex& index) const
    {
        if (!index.isValid()) {
            return Qt::ItemIsDropEnabled;    // Allow drops in the top-level (no parent)
        }
    
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
    }