PyQt5编程(20):拖放技术

使用拖放技术可实现在不同控件或应用之间的数据交换。使用该技术的典型示例是在Windows资源管理器中移动文件。要将文件移动到另一个目录,只需用鼠标左键单击文件图标差按住不放,将文件拖动到目标目录图标,然后释放鼠标按钮。如果要复制文件,而不是移动文件,则还要按住键。
1.拖动
(1) 在mousePressEvent( )中,记录鼠标按下时的位置;
(2) 在mouseMoveEvent ()中,计算鼠标移动的距离,可用来防止无意的拖动。QApplication的下列静态方法可用来控制延迟量:

setstartDragDistance (Distance) - 拖动开始的最小移动量;
startDragDistance() - 返回拖动开始的最小移动量;
setstartDragTime (Time) -拖动开始的按压毫秒数;
startDragTime () - 返回拖动开始的按压毫秒数;

(3) 鼠标移动超过最小移动值或按压鼠标超过最小毫秒数,拖动操作开始。此时,创建一个QDrag对象,调用exce()方法进行相关操作。QDrag有以下方法:

exec( ) -  开始拖放操作,返回一个代表放置操作的枚举值。有两个格式:
exec(supportedActions = Qt.MoveAction)
exec(supportedActions, defaultDropAction)
详细用法参见http://doc.qt.io/qt-5/qdrag.html#exec
setMimeData (QMimeData qmd) - 设置拖放中传输的数据, 参数为QMimeData类型。传输文本的例子:
data = QtCore.QMimeData ()
data.setText ("Drag text")
drag = QtGui.QDrag (self)
drag.setMimeData (data)
mimeData () - 返回拖放过程中传输数据的QMimeData 对象;
setPixmap(QPixmap qpix) - 设定拖放过程鼠标显示的图像。如:
drag.setPixmap (QtGui.QPixmap ("dd representer.png"))
pixmap() - 返回拖放过程中鼠标显示图像的QPixmap对象;
setHotSpot (QPoint pt) - 设置图像的热点位置。
drag.setHotSpot (QtCore.QPoint (20, 20))
hotSpot() - 返回热点位置的QPoint对象;
setDragCursor (QPixmap pix, Qt.DropAction dact) - 设置拖放的鼠标形状。第一个参数为鼠标形状的QPixmap对象;第二参数为相关操作的枚举值,只能是 CopyAction, MoveAction 或LinkAction。drag.setDragCursor (QtGui.QPixmap ("move_cursor.png"), QtCore.Qt.MoveAction)
dragCursor ( Qt.DropAction dact) - 返回dact操作的鼠标形状的QPixmap对象;
source() - 返回源控件的引用;
target() - 返回目标控件的引用。如果拖放的目标对象为另一应用,返回值为None.
supportedActions () - 返回当前有效操作的组合值。
defaultAction () - 返回缺省的操作。

QDrag有两个信号:

actionChanged (Qt.DropAction dact) - 当拖放的行为被该变时,发射该信号;
targetchanged (QWidget obj) - 当目标控件被改变时,将会发射该信号;

2.QMineData类
拖放过过程中的MIME类型的数据传递通过将QMineData对象作为参数调用QDrag的setMimeData()函数实现。
创建QMimeData方法:
data=QtCore.QMimeData()
QMimeData类支持以下方法(详见http://doc.qt.io/qt-5/qmimedata.html):

setText(text) - 设置文本数据(MIME型文本/文本格式):
data.setText("拖动文本")
text( ) - 返回文本数据;
hasText( ) - 如果对象包含文本数据,则返回True,否则返回False。
setHtml(HTML-text) - 以HTML格式设置文本数据(MIME型文本 / html格式):
data.setHtml("拖动HTML文本</ b>")
html( ) - 返回HTML格式的文本数据;
hasHtml( ) - 如果对象包含HTML格式的文本数据,则返回True,否则为False.
setUrls( QList  url) - 设置地址列表,参数为QUrl类的列表;
data.setUrls ([QtCore.QUrl ("http://www.google.com/")])
urls () - 返回地址列表:
url = e.mimeData (). urls () [0] .toString ()
hasUrls () - 如果对象包Url地址,则返回True,否则为False.
setlmageData(QVarinat  img) - 设置图像数据,可以是QImage或QPixmap实例:
data.setlmageData (QtGui.Qlmage("pixmap.png"))
data.setlmageData (QtGui.QPixmap("pixmap.png"))
imageData( ) - 返回图像对象;
haslmage( ) - 如果对象包含图像数据,则返回True,否则为False.
setData(QString mimetype, QCore.QByteData data) 设置任意类型的MIME类型数据;参数1为QString类型,指定MIME类型;参数2为QByteData类实例。该方法可以用MIME不同类型,多次调用:
data.setData("text/plain",QtCore.QByteArray (bytes ("Data", "utf-8")))
data(QString mimetype) -  返回mimetype类型的QByteData数据对象;
hasFormat(QString mimetype) -  如果对象包含mimetype类型数据,则返回True,否则为False.
formats ( ) - 返回包括的mimetype类型列表;
removeFormat (QString mimetype) - 删除mimetype类型的数据;
clear ( ) - 删除所有数据。

如果要实现特殊类型数据的拖放,需要创建一个QMimeData子类,并重载retrieveData( ) 和 formats ( )方法。详细内容,请参考Qt文档。
3. 放置操作
在处理拖放对象之前,必须告诉系统该组件可以处理这些事件。 为此,要在组件的构造函数中,调用继承自QWidget类的setAcceptDrops方法,参数值为True:

self.setAcceptDrops(True)
拖放对象的过程执行如下:

在控件的dragEnterEvent()方法中,检查拖动的MIME类型数据。如果该控件能处理此类型数据,则调用事件对象的acceptProposedAction( )方法。如果要变更操作,则将新事件传递给事件对象的setDropAction( )方法,然后调用accept( )方法,而不是调用acceptProposedAction( )方法。
如果要限制控件的特定区域才能放置操作,必须在dragMoveEvent( )方法中处理。即当拖放进入到特定的区域,调用accept( QRect rect)方法,参数rect为特定区域的QRect对象。
在控件的dropEvent()方法中,完成相关操作。

QWidget类的下列方法可以处理在拖放过程中发生的事件:

    dragEnterEvent (self,event) - 当拖动进入到控件区域时调用。通过event参数, 可取得QDragEnterEvent实例;
    dragLeaveEvent(self,event) - 当拖动离开控件区域时调用。通过event参数, 可取得QDragLeaveEvent实例;
    dragMoveEvent (self, event) -当拖动在控件区域移动时调用。通过event参数, 可取得QDragMoveEvent实例;
    dropEvent (self, event) - 当拖动在控件区域放开时调用。通过event参数, 可取得QDropEvent实例;

QDragLeaveEvent类继承自QEvent类,不附带任何其他信息。因为在该类中只要知道拖动的对象已经离开组件区域就够了。
相关类的继承顺序为:
QEvent - QDropEvent - QDragMoveEvent - QDragEnterEvent
QDragEnterEvent类中没有增加新方法。
QDropEvent类有下列方法:

mimeData( ) - 返回含有所传输数据和MIME类型信息的QMimeData类的实例;
pos( ) - 返回QPoint类的实例,为拖放对象放置的整数坐标;
posF( ) - 返回QPointF类的实例,为拖放对象放置的浮点坐标;
possibleAction( ) - 返回拖放可能的操作组合,如:
if e.possibleActions () & QtCore.Qt.MoveAction:
    print ("MoveAction")
if e.possibleActions () & QtCore.Qt.CopyAction:
    print ("CopyAction")
proposedAction( ) - 返回默认的放置操作;
acceptProposedAction( ) - 表示已准备好接受传输的数据和由proposalAction( )返回的默认操作。该方法(或者accept()方法)必须在dragEnterEvent()中调用,否则,dropEvent()不会被调用。
setDropAction (action) - 允许在放置时指定为action. 作了此设置后,必须调用accept( )方法, 而不是acceptProposedAction( )方法;
dropAction( ) - 返回放置时进行的操作。如果用setDropAction( )进行了更改,可能与proposedAction ()的返回值不一致。
keyboardModifiers( ) - 用于判断按下了哪些修饰键 (, , , 等.) ,可参考“PyQt5编程(18):键盘事件”中的对应函数。
mouseButtons () - 用于判断在拖放过程中按下的鼠标键;
source( ) - 如果拖放是从另一个应用程来的,返回为None;否则,返回对拖放源控件的引用。

QDragMoveEvent类的方法有:

accept (QRect rect) - 表明允许后续的移动操作。 rect用来指定可接受拖放操作的区域;
ignore (QRect rect) - 表明不允许后续的移动操作。 rect用来指定不接受拖放操作的区域;;
answerRect () - 返回可接受拖放操作区域的QRect对象。

PyQt中的有些控件,如单行文本控件,已有拖放功能。因此,在自己实现拖放功能之前,请仔细阅读相关控件的文档。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 禅与 Objective-C 编程艺术 (Zen and the Art of the Objective-C C...
    GrayLand阅读 1,600评论 1 10
  • 当你怀孕以后,到孕中期,肚皮上会出现一条妊娠中线,不同的孕妈咪深浅不一。其实,当你没有怀孕时,它早已存在,而且不分...
    金灶沐_马维阅读 508评论 0 0
  • 迪卡尔曾经说过:阅读好书,就像跟过去最优秀的人物对话。读书的目的是要让我们的人生减少各种不必要的困扰。 在此,我弱...
    迷你花书评阅读 423评论 2 2
  • 在朋友的推荐下开通了简书,开始了我手写我心的尝试。中断了好几年写点什么的习惯,终于又被捡起来,简书让我想起了最...
    Yumi玉米粒阅读 397评论 3 3