《快速掌握PyQt5》第十八章 拖放与剪贴板

第十八章 拖放与剪贴板

18.1 拖放

18.2 剪贴板

18.3 小结


《快速掌握PyQt5》专栏已整理成书出版,书名为《PyQt编程快速上手》,详情请见该链接。感谢大家一直以来的支持!祝大家PyQt用得越来越顺!

拖放和剪贴板的功能原理基础都是QMimeData类,所以这里我们将这两种放在一起讲。QMimeData当然与MIME相关:MIME是描述消息内容类型的因特网标准,可以简单理解为对文件扩展名的详细解释,通过该解释,程序就可以知道应该以何种方式处理该数据。每个MIME类型由两部分组成,前面是数据的大类别,后面定义具体的种类,例如扩展名为.png的MIME类型为image/png;而QMimeData则给记录自身MIME类型的数据提供了一个容器,用于专门处理MIME类型数据。

详细的MIME类型请参考:MIME参考手册

针对常见的MIME类型,QMimeData类提供了很方便的函数用于处理MIME类型数据:

判断函数

获取函数

设置函数

MIME 类型

hasText()

text()

setText()

text/plain

hasHtml()

html()

setHtml()

text/html

hasUrls()

urls()

setUrls()

text/uri-list

hasImage()

imageData()

setImageData()

image/ *

hasColor()

colorData()

setColorData()

application/x-color

18.1 拖放

拖放分为拖动和放下两个动作,它们涉及到以下事件:

  • DragEnterEvent: 所拖动目标进入接收该事件的窗口或控件时触发;
  • DragMoveEvent: 所拖动目标进入窗口或控件后,继续被拖动时触发;
  • DragLeaveEvent: 所拖动目标离开窗口或控件时触发;
  • DropEvent: 所拖动目标被放下时触发。

下面我们完成一个可以实现拖放txt文件并读取的小程序:

import sys
from PyQt5.QtWidgets import QApplication, QTextBrowser


class Demo(QTextBrowser):                                           # 1
    def __init__(self):
        super(Demo, self).__init__()
        self.setAcceptDrops(True)                                   # 2

    def dragEnterEvent(self, QDragEnterEvent):                      # 3
        print('Drag Enter')
        if QDragEnterEvent.mimeData().hasText():
            QDragEnterEvent.acceptProposedAction()

    def dragMoveEvent(self, QDragMoveEvent):                        # 4
        print('Drag Move')

    def dragLeaveEvent(self, QDragLeaveEvent):                      # 5
        print('Drag Leave')

    def dropEvent(self, QDropEvent):                                # 6
        print('Drag Drop')
        # MacOS
        txt_path = QDropEvent.mimeData().text().replace('file:///', '/')

        # Linux
        # txt_path = QDropEvent.mimeData().text().replace('file:///', '/').strip()

        # Windows
        # txt_path = QDropEvent.mimeData().text().replace('file:///', '')

        with open(txt_path, 'r') as f:
            self.setText(f.read())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

1. 继承QTextBrowser,也就是说下面来实现该控件的拖放事件响应函数;

2. setAcceptDrops(True)方法可以让该控件接收放下(Drop)事件;

3. 当拖动目标进入QTextBrowser的那一刹那,触发dragEnterEvent事件,在该响应函数中,我们先判断所拖动目标的MIME类型是否为text/plain,若是的话则调用acceptProposedAction()方法来表明可以在QTextBrowser上进行拖放动作;

4. 当目标进入窗体后,如果不放下而是继续移动的话,则会触发dragMoveEvent事件;

5. 将进入控件后的目标再次拖动到控件之外时,就会触发dragLeaveEvent()事件;

6. 将目标在QTextBrowser中放下后,我们先通过QDropEvent.mimeData().text()方法获取到该文件的URI路径,replace()方法将其中的file:///替换为/,这样得到的值才是我们想要的本地文件路径。最后打开my.txt文件进行读取,并用setText()方法将QTextBrowser的文本设为该my.txt的内容。

注:不同系统使用的路径写法也不同,请注意区分。在Linux上获取的路径中存在'\r\n'所以用strip()去除。

运行截图如下,笔者将放在桌面的my.txt文件拖到程序中,程序显示my.txt文件的内容:

18.2 剪贴板

通常我们在Windows或Linux上使用复制都是按ctrl+c然后按ctrl+v进行粘贴(Mac上为command+c和command+v),这其中就涉及到了剪贴板,当进行复制时,其实是将要复制的内容放到了一个无形的剪贴板上,要粘贴时,再将剪贴板上的内容放到界面上。

当我们浏览CSDN博客,在碰到代码想要复制的时候,右上角会出现一个复制按钮,点击后就可以将所有代码复制到剪贴板上:

我们用PyQt5来实现下类似功能,代码如下:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTextEdit, QTextBrowser, QPushButton, QGridLayout


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.text_edit = QTextEdit(self)
        self.text_browser = QTextBrowser(self)
        
        self.clipboard = QApplication.clipboard()                               # 1
        self.clipboard.dataChanged.connect(lambda: print('Data Changed'))    

        self.copy_btn = QPushButton('Copy', self)                               # 2
        self.copy_btn.clicked.connect(self.copy_func)               

        self.paste_btn = QPushButton('Paste', self)                             # 3
        self.paste_btn.clicked.connect(self.paste_func)

        self.g_layout = QGridLayout()
        self.g_layout.addWidget(self.text_edit, 0, 0, 1, 1)
        self.g_layout.addWidget(self.text_browser, 0, 1, 1, 1)
        self.g_layout.addWidget(self.copy_btn, 1, 0, 1, 1)
        self.g_layout.addWidget(self.paste_btn, 1, 1, 1, 1)
        self.setLayout(self.g_layout)

    def copy_func(self):
        self.clipboard.setText(self.text_edit.toPlainText())

    def paste_func(self):
        self.text_browser.setText(self.clipboard.text())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

1. 实例化一个剪贴板,并将其dataChanged信号和打印函数连接起来。每当剪贴板内容发生变化的时候,都会触发dataChanged信号。在这里也就是说每当发生变化,控制台都会打印出Data Changed;

2. 当点击copy_btn后,槽函数copy_func()就会启动:

def copy_func(self):
    self.clipboard.setText(self.text_edit.toPlainText())

在槽函数中,我们将text_edit中的文本获取过来并通过setText()方法将其设置为剪贴板的文本;

3. 当点击paste_btn后,槽函数paste_func()启动:

def paste_func(self):
    self.text_browser.setText(self.clipboard.text())

在槽函数中,我们将text_browser的文本设为剪贴板的文本。当然该槽函数还有另一种实现方法:

def paste_func(self):
    mime = self.clipboard.mimeData()
    if mime.hasText():
        self.text_browser.setText(mime.text())

首先通过mimeData()方法获取剪贴板内容的MIME类型,然后判断mime类型是否为text/plain,是的话则通过text()方法获取,并设为text_browser文本。

当然以上只是针对文本内容,当然还可以复制图片等文件,而剪贴板当然也有相应的方法,以下列出常用的:

方法解释
clear()清空剪贴板内容
mimeData()获取剪贴板上的MIME类型数据
setMimeData()将MIME类型数据放到剪贴板中
pixmap()获取剪贴板上的QPixmap类型数据
setPixmap()将QPixmap类型数据放到剪贴板中
image()获取剪贴板上的QImage类型数据
setImage()将QImage类型数据放到剪贴板中
text()获取剪贴板上的文本
setText()将文本放到剪贴板中

运行截图如下,在左侧输入文本,点击Copy,再点击Paste,右侧显示相应文本:

18.3 小结

1. 使用QMimeData类来处理MIME类型数据;

2. 拖放事件一共有四种,分别在拖动目标进入窗口或部件时、目标进入后继续被拖动时、目标离开窗口或控件时以及目标被放下时;

2. 剪贴板的内容发生变化的话,则会触发dataChanged信号。剪贴板针对不同数据类型有相应获取和设置的方法。

欢迎关注我的微信公众号,发现更多有趣内容:

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

la_vie_est_belle

谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值