简体   繁体   English

Qt QTreeView:只允许放置在现有项目上

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

I've got a custom model inherited from QTreeView.我有一个从 QTreeView 继承的自定义模型。 I've enabled drag and drop and can currently drop an item onto the tree.我已启用拖放功能,目前可以将项目拖放到树上。 However, you can currently drop onto either an existing item or between items.但是,您当前可以放置在现有项目上或项目之间。 I would like to restrict this so that you can only drop onto existing items.我想限制这一点,以便您只能放下现有项目。

I've set DragDropOverwriteMode to true (actually this is the default for QTreeView).我已将 DragDropOverwriteMode 设置为 true(实际上这是 QTreeView 的默认设置)。 However, this doesn't stop you from dropping between items - it just means you can also drop onto existing items.但是,这并不能阻止您在物品之间掉落 - 这只是意味着您也可以掉落到现有物品上。

I know that I can ignore the "insert" drops in dropMimeData (which I am reimplementing), by checking whether row and column are valid (drops onto existing items have row and column set to -1 and parent set to the current item) and I am doing this.我知道我可以忽略 dropMimeData(我正在重新实现)中的“插入”删除,通过检查行和列是否有效(删除到现有项目的行和列设置为 -1,父项设置为当前项目)和我正在这样做。 However, I would prefer not to get these drops.但是,我不想得到这些滴。 Ie. IE。 I would like it so that you are always dropping over either the item above or the item below, never between items.我希望你总是从上面的项目或下面的项目上掉下来,而不是在项目之间。

Any ideas?有任何想法吗?

Thanks for any advice, Giles感谢您的任何建议,吉尔斯

As of Qt 5.4 (and I assume this was true even in Qt 4.8), setting DragDropOverwriteMode to true will correctly cause the drags to be droppable only on existing items and prevents the "above/below items" drop targets from appearing.从 Qt 5.4 开始(我认为即使在 Qt 4.8 中也是如此),将DragDropOverwriteMode设置为true正确地导致拖动只能在现有项目上放置,并防止出现“项目上方/下方”放置目标。

Also, unlike what the question claims, DragDropOverwriteMode is set to false by default for QTreeView (I didn't check, maybe it's newer Qt versions), so it needs to be set to true manually.此外,与问题所声称的不同,默认情况下, QTreeView DragDropOverwriteMode设置为false (我没有检查,可能是较新的 Qt 版本),因此需要手动将其设置为true

However it is still useful to be able to calculate on what positions the item can be dropped.然而,能够计算物品可以被丢弃的位置仍然很有用。 For example in QTreeView, one cannot drop a dragged thing on the left margin of the items, ie the red area below:例如在QTreeView中,不能在items的左边距放置拖拽的东西,即下面的红色区域:

QTreeView 无效放置区域

If something is dropped in the invalid red area, dropMimeData will be called with a parent argument set to NULL .如果在无效的红色区域中dropMimeData则将调用dropMimeData并将parent参数设置为NULL So it would be useful to ignore the dragMoveEvent in advance to show a 'you can't drop here' cursor to the user so they know they can't drop there.因此,提前ignore dragMoveEvent以向用户显示“你不能放在这里”光标会很有用,这样他们就知道他们不能放那里。 Qt doesn't implement changing the mouse cursor on invalid areas while dragging (as of Qt 5.4), but we can do it like this: 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;
}

The above code contains a little part visualRect….adjusted(-1, -1, 1, 1) which was stolen from QAbstractItemViewPrivate::position sources.上面的代码包含一小部分visualRect….adjusted(-1, -1, 1, 1) ,它是从QAbstractItemViewPrivate::position源中窃取的。 Actually the sources of this function can be used to calculate the overwrite/insert/invalid areas for the item when QAbstractItemViewPrivate::position is false too.实际上,当QAbstractItemViewPrivate::positionfalse时,此函数的来源也可用于计算项目的覆盖/插入/无效区域。

You'' need to catch the drag enter events by reimplementing the dragEnterEvent method in your custom view.您需要通过在自定义视图中重新实现dragEnterEvent方法来捕获拖动输入事件。 The example from the Qt docs is: Qt 文档中的示例是:

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

In your case, you would probably need to compare the x and y position in the event with the x and y position of the closest item or something similar and reject or accept the proposed action based on that information.在您的情况下,您可能需要将事件中的 x 和 y 位置与最近项目的 x 和 y 位置或类似的东西进行比较,然后根据该信息拒绝或接受建议的操作。

From the QAbstractItemModel::dropMimeData documentation:QAbstractItemModel::dropMimeData文档:

It is the responsibility of the view to provide a suitable location for where the data should be inserted.视图有责任为应插入数据的位置提供合适的位置。

Which I have interpreted to mean that the view should reject the drop if it's not something that's supported by an underlying model, such as yours.我已经解释为,如果它不是由基础模型(例如您的模型)支持的内容,则视图应该拒绝删除。

I would like to suggest a solution based on the current position of the drop indicator ( QAbstractItemView::DropIndicatorPosition ).我想根据放置指示器的当前位置 ( QAbstractItemView::DropIndicatorPosition ) 提出一个解决方案。 It's pretty simple to implement, but unfortunately requires the drop indicator to be shown.实现起来非常简单,但不幸的是需要显示放置指示器。 However, this might be acceptable in some cases.但是,这在某些情况下可能是可以接受的。

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