簡體   English   中英

Qt QTreeView:只允許放置在現有項目上

[英]Qt QTreeView: Only allow to drop on an existing item

我有一個從 QTreeView 繼承的自定義模型。 我已啟用拖放功能,目前可以將項目拖放到樹上。 但是,您當前可以放置在現有項目上或項目之間。 我想限制這一點,以便您只能放下現有項目。

我已將 DragDropOverwriteMode 設置為 true(實際上這是 QTreeView 的默認設置)。 但是,這並不能阻止您在物品之間掉落 - 這只是意味着您也可以掉落到現有物品上。

我知道我可以忽略 dropMimeData(我正在重新實現)中的“插入”刪除,通過檢查行和列是否有效(刪除到現有項目的行和列設置為 -1,父項設置為當前項目)和我正在這樣做。 但是,我不想得到這些滴。 IE。 我希望你總是從上面的項目或下面的項目上掉下來,而不是在項目之間。

有任何想法嗎?

感謝您的任何建議,吉爾斯

從 Qt 5.4 開始(我認為即使在 Qt 4.8 中也是如此),將DragDropOverwriteMode設置為true正確地導致拖動只能在現有項目上放置,並防止出現“項目上方/下方”放置目標。

此外,與問題所聲稱的不同,默認情況下, QTreeView DragDropOverwriteMode設置為false (我沒有檢查,可能是較新的 Qt 版本),因此需要手動將其設置為true

然而,能夠計算物品可以被丟棄的位置仍然很有用。 例如在QTreeView中,不能在items的左邊距放置拖拽的東西,即下面的紅色區域:

QTreeView 無效放置區域

如果在無效的紅色區域中dropMimeData則將調用dropMimeData並將parent參數設置為NULL 因此,提前ignore dragMoveEvent以向用戶顯示“你不能放在這里”光標會很有用,這樣他們就知道他們不能放那里。 Qt 沒有實現在拖動時更改無效區域上的鼠標光標(從 Qt 5.4 開始),但我們可以這樣做:

bool SubclassedTreeView::dropResultsInValidIndex(const QPoint& pos)
{
    QTreeWidgetItem* item = itemAt(pos);
    if (item == NULL || !indexFromItem(item).isValid())
        return false;
    return visualRect(indexFromItem(item)).adjusted(-1, -1, 1, 1).contains(pos, false);
}

virtual void SubclassedTreeView::dragMoveEvent(QDragMoveEvent* event)
{
    QTreeWidget::dragMoveEvent(event);
    if (!event->isAccepted())
        return;

    if (dropResultsInValidIndex(event->pos()))
        event->accept();
    else
        event->ignore(); //Show 'forbidden' cursor.
}

virtual bool SubclassedTreeView::dropMimeData(QTreeWidgetItem* parent, int index, const QMimeData* data, Qt::DropAction action)
{
    Q_UNUSED(index);
    //Modify the following action and data format checks to suit your needs:
    if (parent == NULL || action != Qt::CopyAction || !data->hasFormat("my/preferred-type"))
        return false;

    QModelIndex modelIndex = indexFromItem(parent);
    //modelIndex is where the data is dropped onto. Implement your custom drop action here...

    return true;
}

上面的代碼包含一小部分visualRect….adjusted(-1, -1, 1, 1) ,它是從QAbstractItemViewPrivate::position源中竊取的。 實際上,當QAbstractItemViewPrivate::positionfalse時,此函數的來源也可用於計算項目的覆蓋/插入/無效區域。

您需要通過在自定義視圖中重新實現dragEnterEvent方法來捕獲拖動輸入事件。 Qt 文檔中的示例是:

void Window::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat("text/plain"))
        event->acceptProposedAction();
}

在您的情況下,您可能需要將事件中的 x 和 y 位置與最近項目的 x 和 y 位置或類似的東西進行比較,然后根據該信息拒絕或接受建議的操作。

QAbstractItemModel::dropMimeData文檔:

視圖有責任為應插入數據的位置提供合適的位置。

我已經解釋為,如果它不是由基礎模型(例如您的模型)支持的內容,則視圖應該拒絕刪除。

我想根據放置指示器的當前位置 ( QAbstractItemView::DropIndicatorPosition ) 提出一個解決方案。 實現起來非常簡單,但不幸的是需要顯示放置指示器。 但是,這在某些情況下可能是可以接受的。

TreeView::TreeView(QWidget* parent) : QTreeView(parent)
{
    setDropIndicatorShown(true);
}

void TreeView::dragMoveEvent(QDragMoveEvent* event)
{
    QTreeView::dragMoveEvent(event);

    if (dropIndicatorPosition() != QTreeView::OnItem)
        event->setDropAction(Qt::IgnoreAction);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM