【问题标题】:Qt QTreeView: Only allow to drop on an existing itemQt QTreeView:只允许放在现有项目上
【发布时间】:2011-10-20 00:05:08
【问题描述】:

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

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

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

有什么想法吗?

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

【问题讨论】:

  • 现在找到答案。请参阅对马特回答的评论。

标签: c++ qt qtreeview


【解决方案1】:

我想根据下降指示器的当前位置提出一个解决方案 (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);
}

【讨论】:

    【解决方案2】:

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

    另外,与问题所声称的不同,DragDropOverwriteMode 默认设置为false QTreeView(我没有检查,可能是较新的 Qt 版本),因此需要将其设置为 true手动。

    但是,能够计算出可以丢弃物品的位置仍然很有用。例如在QTreeView中,不能将拖拽的东西放到item的左边距,即下面的红色区域:

    如果在无效的红色区域中放置了某些东西,则将调用 dropMimeData,并将 parent 参数设置为 NULL。因此,提前ignoredragMoveEvent 向用户向用户显示“你不能放在这里”光标会很有用,这样他们就知道他们不能放在那里。 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时,这个函数的来源可以用来计算item的覆盖/插入/无效区域。

    【讨论】:

      【解决方案3】:

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

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

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

      来自QAbstractItemModel::dropMimeData 文档:

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

      我的解释是,如果它不是底层模型(例如您的模型)支持的东西,视图应该拒绝丢弃。

      【讨论】:

      • 感谢您的回复和有用的信息。 dragEnterEvent 不适合,因为它仅在您第一次拖动小部件时调用,而不是在鼠标移动到小部件上时重复调用。但是,dragMoveEvent 方法确实会被重复调用,所以我想我可以使用它。
      • 将 moveEvent 的矩形与树中所有项目的矩形进行比较似乎过于复杂。有没有更简单的方法来确定我是否在一个项目上而不是在项目之间?我看过 dropIndicatorPosition 听起来它应该做正确的事情。但是,无论我是在一个项目上还是在项目之间,它总是返回 0。任何建议将不胜感激。
      • 我现在找到了一种更简单的方法,它完全符合我的要求。重新实现底层模型的 flags 方法以仅在传递的索引有效时返回 Qt::ItemIsDropEnabled。在项目之间时,使用无效索引调用 flags(),因此我可以决定不接受丢弃。
      • 很高兴你找到了它。现在我为自己的模型和视图实现学到了一些东西。 :)
      • 反之,你可以这样做: if ( index.isValid() ) { return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled; } 其他 { 返回 Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled;这对我帮助很大:)!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-14
      • 2014-01-03
      • 2015-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多