Qt拖放:启用复制时无法移动(Ubuntu Gnome)

Posted

技术标签:

【中文标题】Qt拖放:启用复制时无法移动(Ubuntu Gnome)【英文标题】:Qt drag/drop: cannot move when copy is enabled (Ubuntu Gnome) 【发布时间】:2012-07-04 12:55:16 【问题描述】:

我正在实现一个视图和一个模型,我希望在其中支持在内部移动项目(通过拖动)和复制项目(通过在拖动时按 Ctrl)。我已经按照说明完成了我需要做的所有事情。我已经设置了 mime 函数,我已经实现了 removeRows() 和 flags()。问题是当我拖动时,它默认为复制操作(我得到带有加号的箭头光标,它确实通过在模型中创建一个新项目来复制项目)。

我能看到的唯一区别是:如果我在supportedDropActions() 中只返回Qt::MoveAction,它只会移动。如果我返回 (Qt::CopyAction | Qt::MoveAction),它只会复制。

有什么想法吗?我希望它像 Nautilus (Gnome) 或 Windows 文件资源管理器中的文件一样工作:拖动移动图标,ctrl+drag 复制它们。

【问题讨论】:

同样的问题出现在 Windows 上,但Qt::MoveAction 是首选。 如果有人愿意,我可以发布一些示例代码来演示问题。 既然这最终没有回答我的问题,谁觉得他们应该得到赏金? 我是在 Qt 4.7 中将 setDefaultDropAction() 添加到 QAbstractItemView 的人,这是否意味着我应该得到赏金? :-) 大卫,我会考虑给你赏金,但我没有发布它,我什至不知道它,而且它看起来在发布一个月后就结束了。无论如何,感谢您对 Qt 和 KDE 的贡献! (附带说明一下,它仍然困扰着我——有 SIX (6) 个与项目视图的拖放相关的属性!六个!acceptDrops、showDropIndicator、dragEnabled、dragDropOverwriteMode、dragDropMode 和您的defaultDropAction。当然还有一连串代码要编写来执行 MIME 类型,使用 removeRows()、flags() ——就像我说我喜欢 Qt 但哇,拖放很复杂!) 【参考方案1】:

很抱歉,当我发现我做错了什么时,我没有回答这个问题。把我搞砸的代码在QAbstractItemView::startDrag()

if (d->defaultDropAction != Qt::IgnoreAction && (supportedActions & d->defaultDropAction))
        defaultDropAction = d->defaultDropAction;
    else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
        defaultDropAction = Qt::CopyAction;

问题是我没有像setDefaultDropAction( Qt::MoveAction ); 那样在小部件上设置 defaultDropAction 属性,因此 startDrag() 默认为 CopyAction。如果 defaultDropAction 是 Qt::MoveAction,那么您可以使用键盘 Ctrl 将正在进行的拖动切换到复制操作,这是我想要的行为。

我喜欢 Qt,但肯定有很多与拖放相关的令人困惑且有些相互交织的属性。很容易得不到正确的属性组合。

底线:确保将 defaultDropAction 设置为 Qt::MoveAction

【讨论】:

只是为了提供更多信息,我必须在 listView 上更改的属性如下:acceptDrops:true,dragEnabled:true,defaultDropAction:MoveAction(这是大的!),selectionMode : ExtendedSelection(也是预期的 Windows Explorer 行为,但不是 QListView 的默认行为)。同样在模型中:setSupportedDragActions(Qt::CopyAction | Qt::MoveAction);,返回 Qt::CopyAction | MyModel::Model::supportedDropActions() 中的 Qt::MoveAction,将 Qt::ItemIsDragEnabled 添加到 MyModel::flags(),实现 MyModel::mimeTypes()、mimeData() 和 dropMimeData。希望有帮助! 这意味着我遇到的错误实际上与您遇到的不同。它看起来像 Windows 上的 Qt 错误。 DK,我很好奇——它是通常基于mingw的Qt SDK(创建者),还是使用Visual Studio编译的Qt(基于WinAPI ?)。另外,我的问题是,使用 Copy 作为默认行为,我根本无法实现 Move,因为没有键盘修饰符可以将 Copy 更改为 Move。你说你Move有问题--那能不能不按住Ctrl改成Copy? 经过更多的实验,似乎 Qt 正在强制外部放置目标决定它想对文件做什么。如果我将文件拖到资源管理器中的任何位置,它会强制使用Qt::TargetMoveAction,但如果我将它拖到 Chromium 上,它会强制使用Qt::CopyAction。键盘修饰符确实有效,但理想情况下,它们不应该是实现正确放置动作所必需的。我正在使用PySide,我相信它会基于mingw。 这看起来确实很奇怪——我不确定为什么放置目标会决定(至少对于默认值)源应该保留其副本(如在 CopyAction 中)还是删除它(如在 MoveAction 中)。看起来这对放置目标没有任何影响。【参考方案2】:

如果你尝试这种方式会怎样 先写一个keyPressEvent,设置是否按下ctrl键 '

keyPressEvent(QKeyEvent *e)
    
        if(e->key() == Qt::Key_Control)
            bControlKeyPressed = true;
    
    keyReleaseEvent (QKeyEvent *e)
    
       if(e->key() == Qt::Key_Control)
          bControlKeyPressed = false;
    

并在鼠标按下事件中检查是否按下了 ctrl 键

`mousePressEvent()
 
  if (bControlKeyPressed) 
    //enable Qt::CopyAction 
else 
    //enable  Qt::MoveAction 
` 

【讨论】:

这样简单的答案是理想的,但 Ubuntu/Windows 只是忽略指定的操作(以及默认操作)。【参考方案3】:

这就是我会做的:

启用复制操作。然后收听拖放信号或覆盖虚拟方法(或任何 Qt 提供的,我没有检查),如果您的意思是移动,请“手动”删除该行。放下后,保存您喜欢的操作。

如果无法从 Qt 数据中确定所需的操作,请检查 Ctrl 键状态并保存一个布尔值,说明它是复制还是移动。现在,当 Qt 发出信号被删除时,检查您选择的操作,然后自己删除移动的行。

(我个人使用 gtkmm,copy-if-Ctrl-is-pressed 效果很好)

【讨论】:

这个解决方案确实有些工作,但有两个问题: a) 拖动图标不正确。 b) 如果选择了多个项目,在它们之间拖动它们会删除一些并复制其他的。 那么我看到了两个选项。 1)just-get-rid-of-it 方法:手动设置图标。对于多选,请自行处理 drop。决定如何移动/复制每个节点。它可能很复杂,这取决于 Qt 如何让您访问拖放数据...... 2)严肃的工程师方法:找出为什么这不能像他们应该的那样工作。 Qt 是免费软件,所以如果有错误,请调查是否可以解决。因此,您为 Qt 的所有用户和使用 Qt 编写的任何应用程序做出了贡献。并且永远不需要任何变通方法。 如果 Windows 内部有问题,您能做的最好的事情就是向他们发送电子邮件。 Windows 是专有软件,所以我认为这是他们的问题,而不是我的问题或你的问题,如果 D&D 不能正常工作的话。或在您的代码中添加临时解决方法,仅适用于 Windows

以上是关于Qt拖放:启用复制时无法移动(Ubuntu Gnome)的主要内容,如果未能解决你的问题,请参考以下文章

Ubuntu22.04 在 VMware 17 无法实现拖放复制操作解决办法

新的拖放机制在 Qt-Quick (Qt 5.3) 中无法按预期工作

ubuntu使用了无效的拖放类型

Qt 视图框架QGraphicsItem

Win7系统VirtualBox虚拟机的Ubuntu无法使用复制粘贴怎么办

无法在 AEM 新页面上拖放组件