拖放(01):【纲】Drag and Drop [官翻]

文章目录

  • 拖放类
  • 配置
  • 在Qt Quick中拖放
  • 拖曳Dragging
  • 放置Dropping
    • 重载 Proposed Actions
    • 子类化复杂小部件
  • 拖放动作
  • 添加新的拖放类型
  • 放置动作Drop Actions
  • 放置矩形
  • 剪贴板
  • 例子
  • 与其他应用程序的互操作

Drag and Drop

拖放提供了一种简单的可视化机制,用户可以使用它在应用程序之间和应用程序内部传输信息。拖放功能类似于剪贴板的剪切和粘贴机制,均是以QMimeData类为基础的。

本文档介绍了基本的拖放机制,并概述了在自定义控件中启用它的方法。

Qt的许多控件( 例如项目视图和图形视图框架 )以及 Qt Widgets 和 Qt Quick 的编辑控件也支持拖放操作。有关在项目视图和图形视图框架中使用拖放的信息,请参见有关项目视图图形视图的更多信息。

拖放类

下列这些类处理拖放以及必要的mime类型编码和解码。

类名 说明
QDrag 支持基于MIME的拖放数据传输
QDragEnterEvent 拖放动作进入小部件时发送给小部件的事件
QDragLeaveEvent 拖放操作离开小部件时发送给小部件的事件
QDragMoveEvent 进行拖放操作时发送的事件
QDropEvent 表示已开始拖动主图标

配置

QStyleHints 对象提供一些相关的拖放操作特性:

  • QStyleHints::startDragTime()描述了用户在拖动开始之前必须在对象上按住鼠标按钮的时间(以毫秒为单位)。

  • QStyleHints::startDragDistance()指示用户必须按住鼠标键的同时将鼠标移动多远,然后移动才会被解释为拖动。

  • QStyleHints::startDragVelocity()指示用户移动鼠标以开始拖动的速度(以像素/秒为单位)。值0的意思是没有这样的限制。

如果控件提供拖放支持,则这些方法提供了与基础窗口系统兼容的合理默认值,供您使用。

在Qt Quick中拖放

本文档的其余部分主要关注如何在C++中实现拖放。要在 Qt Quick 场景中使用拖放功能,请阅读有关Qt Quick Drag,DragEvent和DropArea 项的文档,以及Qt Quick Drag and Drop示例。

拖曳Dragging

要开始拖动,请创建QDrag对象,然后调用其exec()函数。在大多数应用程序中,最好仅在按下鼠标按钮并且将光标移动了一定距离之后才开始拖放操作。但是,启用从窗口小部件拖动的最简单方法是重新实现窗口小部件的mousePressEvent()并开始拖放操作:

尽管用户可能需要一些时间来完成拖动操作,但就应用程序而言,exec()函数是一个阻塞函数,它返回几个值之一。这些指示操作如何结束,下面将进行详细说明。

请注意,exec()函数不会阻止主事件循环。

对于需要区分鼠标单击和拖动的窗口小部件,重新实现窗口小部件的mousePressEvent()函数以记录拖动的开始位置非常有用:

稍后,在mouseMoveEvent()中,我们可以确定是否应该开始拖动,并构造一个拖动对象来处理该操作:

这种特殊的方法使用QPoint::manhattanLength()函数来大致估计鼠标单击发生的位置与当前光标位置之间的距离。此功能以准确性为代价,通常适合于此目的。

放置Dropping

为了能够接收放置在窗口小部件上的媒体,请为窗口小部件调用setAcceptDrops(true),然后重新实现dragEnterEvent()和dropEvent()事件处理函数。

例如,以下代码在QWidget子类的构造函数中启用放置事件,从而可以有效地实现放置事件处理程序:

dragEnterEvent()函数通常用于通知Qt有关小部件接受的数据类型。如果要在dragMoveEvent()和dropEvent()的重新实现中接收QDragMoveEvent或QDropEvent,则必须重新实现此函数。

以下代码显示了如何重新实现dragEnterEvent()来告诉拖放系统我们只能处理纯文本:

dropEvent()用来解包放置的数据,使用适合您的应用程序的方式处理它。

在下面的代码中,事件中提供的文本将传递到QTextBrowser,并且QComboBox会填充用于描述数据的MIME类型的列表:

在这种情况下,我们接受建议的操作而不检查它是什么。在实际的应用程序中,可能需要从dropEvent()函数返回而不接受建议的操作或不处理该数据(如果该操作不相关)。例如,如果我们不支持在应用程序中指向外部源的链接,则可以选择忽略Qt::LinkAction操作。

重载 Proposed Actions

我们也可能忽略建议的操作,并对数据执行其他操作。为此,我们将在调用accept()之前,使用Qt::DropAction的首选操作调用事件对象的setDropAction()。这样可以确保使用替换放置动作代替提议的动作。

对于更复杂的应用程序,重新实现dragMoveEvent()和dragLeaveEvent()可使您使小部件的某些部分对放置事件敏感,并使您可以更好地控制应用程序中的拖放。

子类化复杂小部件

某些标准Qt小部件提供了自己的拖放支持。在子类化这些小部件时,除dragEnterEvent()和dropEvent()外,可能还需要重新实现dragMoveEvent(),以防止基类提供默认的拖放处理,并处理您感兴趣的任何特殊情况。

拖放动作

在最简单的情况下,拖放操作的目标将收到要拖动的数据的副本,而源将决定是否删除原始数据。这由操作来描述。目标还可以选择处理其他动作,特别是和动作。如果源调用QDrag::exec()并返回,则源负责选择删除任何原始数据。源小部件创建的QMimeData和QDrag对象不应删除-它们将被Qt破坏。目标负责获取在拖放操作中发送的数据的所有权;这通常是通过保留对数据的引用来完成的。

如果目标了解该操作,则应存储其对原始信息的引用;源不需要对数据进行任何进一步的处理。拖放操作最常见的用法是在同一小部件中执行“移动”时;有关此功能的更多信息,请参见“放置动作”部分。

拖动动作的另一个主要用途是使用诸如文本/uri-list之类的引用类型时,其中拖动的数据实际上是对文件或对象的引用。

添加新的拖放类型

拖放不仅限于文本和图像。任何类型的信息都可以通过拖放操作进行传输。为了在应用程序之间拖动信息,应用程序必须能够相互指示它们可以接受哪些数据格式以及可以产生哪些数据格式。这是使用MIME类型实现的。由源构造的QDrag对象包含用于表示数据的MIME类型列表(从最合适的到最不合适的顺序),放置目标使用其中之一来访问数据。对于常见的数据类型,便捷功能处理透明使用的MIME类型,但是对于自定义数据类型,必须明确声明它们。

要对QDrag便利功能未涵盖的信息类型执行拖放操作,第一步也是最重要的一步是寻找合适的现有格式:Internet分配号码授权机构(IANA)提供了以下内容的层次结构列表:信息科学研究所(ISI)的MIME媒体类型。现在和将来,使用标准的MIME类型都会使您的应用程序与其他软件的互操作性最大化。

要支持其他媒体类型,只需使用setData()函数在QMimeData对象中设置数据,即可提供完整的MIME类型和一个包含适当格式数据的QByteArray。以下代码从标签中获取一个像素图,并将其作为可移植网络图形(PNG)文件存储在QMimeData对象中:

当然,对于这种情况,我们可以简单地使用setImageData()来提供各种格式的图像数据:

在这种情况下,QByteArray方法仍然有用,因为它可以更好地控制QMimeData对象中存储的数据量。

请注意,项目视图中使用的自定义数据类型必须声明为元对象,并且必须实现它们的流运算符。

放置动作Drop Actions

在剪贴板模型中,用户可以剪切或复制源信息,然后粘贴。类似地,在拖放模型中,用户可以拖动信息的副本,也可以将信息本身拖动到新的位置(移动它)。拖放模型给程序员带来了一个额外的麻烦:在操作完成之前,程序不知道用户是要剪切还是复制信息。在应用程序之间拖动信息时,这通常没有什么区别,但是在应用程序内部,重要的是检查使用了哪个放置动作。

我们可以为小部件重新实现mouseMoveEvent(),并通过可能的放置动作的组合来开始拖放操作。例如,我们可能要确保拖动始终在小部件中移动对象:

来源:hitzsf

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年11月7日
下一篇 2020年11月7日

相关推荐