Search code examples
qtdrag-and-dropqtreewidgetqtreewidgetitem

Show ForbiddenCursor only when mouse is OnItem in QTreeWidget


I am trying to display the Qt::ForbiddenCursor when I move a mouse over an item in a custom QTreeWidget but only when drop position is QAbstractItemView::OnItem. Here is the code

    void XProjectTreeWidget::dragMoveEvent(QDragMoveEvent * event)
{
    QTreeWidgetItem* pItem = itemAt(event->pos());
    if (pItem == nullptr)
    {
        return;
    }

    XTreeItem* dropItem = dynamic_cast<XTreeItem*>(pItem);
    if (dropItem == nullptr)
    {
        return;
    }

    XTreeItem::DropPosition drop;
    if (!getDropPosition(drop))
    {
        return;
    }

    auto items = selectedItems();
    if (items.count() == 0)
    {
        return;
    }

    auto dragItem = (XTreeItem*)items.first();
    if (!dragItem->checkMoveItemPossible(dropItem, drop))
    {
        QGuiApplication::changeOverrideCursor(QCursor(Qt::ForbiddenCursor));
        event->setDropAction(Qt::IgnoreAction);
    }
    else
    {
        QGuiApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor));
        event->setDropAction(Qt::MoveAction);
    }

    QTreeWidget::dragMoveEvent(event);
}

bool XProjectTreeWidget::getDropPosition(XTreeItem::DropPosition& drop)
{
    DropIndicatorPosition dropIndicator = dropIndicatorPosition();
    switch (dropIndicator)
    {
        case QAbstractItemView::AboveItem:  drop = XTreeItem::Above; break;
        case QAbstractItemView::BelowItem:  drop = XTreeItem::Below; break;
        case QAbstractItemView::OnItem:     drop = XTreeItem::Inside; break;
        default: return false;
    }
    return true;
}

The problem is that the ignore action seems to be applied to all the items with the same type for AboveItem and BelowItem. dragMoveEvent is called when the DropPosition is OnItem for the items with the same type while hovering the cursor above those items.

How can I show ForbiddenCursor only when mouse is OnItem?


Solution

  • Calling QTreeWidget::dragMoveEvent(event); before changing the cursors fixed the issue. Here is how the fixed code looks now:

    void XProjectTreeWidget::dragMoveEvent(QDragMoveEvent * event)
    {
        // moved this call from the end of the method
        QTreeWidget::dragMoveEvent(event);
    
        QTreeWidgetItem* pItem = itemAt(event->pos());
        if (pItem == nullptr)
        {
            return;
        }
    
        XTreeItem* dropItem = dynamic_cast<XTreeItem*>(pItem);
        if (dropItem == nullptr)
        {
            return;
        }
    
        XTreeItem::DropPosition drop;
        if (!getDropPosition(drop))
        {
            return;
        }
    
        auto items = selectedItems();
        if (items.count() == 0)
        {
            return;
        }
    
        auto dragItem = (XTreeItem*)items.first();
        if (!dragItem->checkMoveItemPossible(dropItem, drop))
        {
            QGuiApplication::changeOverrideCursor(QCursor(Qt::ForbiddenCursor));
            event->setDropAction(Qt::IgnoreAction);
        }
        else
        {
            QGuiApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor));
            event->setDropAction(Qt::MoveAction);
        }
    }