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

发布于 2024-11-28 01:31:25 字数 390 浏览 4 评论 0原文

我有一个继承自 QTreeView 的自定义模型。我已启用拖放功能,当前可以将项目拖放到树上。但是,您当前可以拖放到现有项目上或项目之间。我想限制这一点,以便您只能放置到现有的项目上。

我已将 DragDropOverwriteMode 设置为 true (实际上这是 QTreeView 的默认设置)。然而,这并不能阻止您在项目之间放置 - 它只是意味着您也可以放置在现有项目上。

我知道我可以通过检查行和列是否有效来忽略 dropMimeData 中的“插入”滴(我正在重新实现)(滴到现有项目上的行和列设置为 -1,父级设置为当前项目)并且我正在做这个。然而,我不想得到这些滴。 IE。我希望这样您总是可以跳过上面的项目或下面的项目,而不是在项目之间。

有什么想法吗?

感谢您的任何建议, 贾尔斯

I've got a custom model inherited from 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). 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. However, I would prefer not to get these drops. 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

尽揽少女心 2024-12-05 01:31:25

您需要通过在自定义视图中重新实现 dragEnterEvent 方法来捕获拖动输入事件。 Qt 文档中的示例是:

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

在您的情况下,您可能需要将事件中的 x 和 y 位置与最近项目或类似内容的 x 和 y 位置进行比较,并根据该信息拒绝或接受建议的操作。

来自 QAbstractItemModel::dropMimeData 文档:

视图有责任为数据插入提供合适的位置。

我将其解释为,如果底层模型(例如您的模型)不支持该视图,则该视图应该拒绝该放置。

You'' need to catch the drag enter events by reimplementing the dragEnterEvent method in your custom view. The example from the Qt docs is:

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.

From the QAbstractItemModel::dropMimeData documentation:

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.

在巴黎塔顶看东京樱花 2024-12-05 01:31:25

从 Qt 5.4 开始(我认为即使在 Qt 4.8 中也是如此),将 DragDropOverwriteMode 设置为 true正确导致拖动可放置仅在现有项目上,并防止出现“上方/下方项目”放置目标。

另外,与问题所声称的不同,QTreeViewDragDropOverwriteMode默认设置为false(我没有检查,也许是较新的Qt版本),所以需要手动设置为true

然而,能够计算出物品可以掉落的位置仍然很有用。例如,在 QTreeView 中,不能将拖动的东西放在项目的左边距,即下面的红色区域:

QTreeView 无效放置区域

如果在无效的红色区域中放置了某些内容,dropMimeData将使用设置为 NULLparent 参数进行调用。因此,提前忽略 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::position 为 false 时,该函数的源也可用于计算项目的覆盖/插入/无效区域。

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.

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.

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, i.e the red area below:

QTreeView invalid drop areas

If something is dropped in the invalid red area, dropMimeData will be called with a parent argument set to 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. 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:

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. 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.

花间憩 2024-12-05 01:31:25

我想建议一个基于放置指示器当前位置的解决方案(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);
}

I would like to suggest a solution based on the current position of the drop indicator (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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文