文章目录
- 前言
- [一、QMimeData 基础](#一、QMimeData 基础)
-
- [1.什么是 MIME 类型](#1.什么是 MIME 类型)
- [2.QMimeData 类的基本功能](#2.QMimeData 类的基本功能)
- [3.QMimeData 的内部结构](#3.QMimeData 的内部结构)
- [4.QMimeData 的实际应用](#4.QMimeData 的实际应用)
- 二、剪贴板(Clipboard)
-
- [1.获取 QClipboard 实例](#1.获取 QClipboard 实例)
- 2.基本数据类型操作
- 3.实践操作
- 总结
前言
PySide6中剪贴板(Clipboard)和拖曳(Drag and Drop)是两种常用的数据交换机制。它们允许在应用程序内部或不同应用程序之间传输数据,本节将分别详细介绍这两个主题。
一、QMimeData 基础
无论是拖曳还是剪贴板都需要将 QMimeData 作为数据传输中介,QMimeData 是 Qt 中用于封装 MIME 类型数据的类,它是剪贴板和拖放操作的数据传输核心。MIME(Multipurpose Internet Mail Extensions)最初用于电子邮件,现在被广泛用于描述数据类型。
1.什么是 MIME 类型
MIME 类型是一种标准化的方式,用于标识数据的格式。格式为:type / subtype;
常见 MIME 类型:
① text/plain - 纯文本;
② text/html - HTML 文本;
③ text/uri-list - URL 列表;
④ image/png - PNG 图像;
⑤ image/jpeg - JPEG 图像;
⑥ application/octet-stream - 二进制数据;
⑦ application/json - JSON 数据。
2.QMimeData 类的基本功能
python
from PySide6.QtCore import QMimeData, QByteArray
# 创建 QMimeData 对象
mime_data = QMimeData()
# 1. 设置标准数据
mime_data.setText("Hello World") # 设置纯文本
mime_data.setHtml("<b>Hello</b> World") # 设置 HTML
mime_data.setUrls([QUrl("file:///path/to/file")]) # 设置 URL 列表
mime_data.setImageData(pixmap.toImage()) # 设置图像数据
mime_data.setColorData(QColor(255, 0, 0)) # 设置颜色数据
# 2. 检查数据
has_text = mime_data.hasText() # 检查是否有文本
has_html = mime_data.hasHtml() # 检查是否有 HTML
has_urls = mime_data.hasUrls() # 检查是否有 URL
has_image = mime_data.hasImage() # 检查是否有图像
has_color = mime_data.hasColor() # 检查是否有颜色
has_format = mime_data.hasFormat("text/plain") # 检查特定格式
# 3. 获取数据
text = mime_data.text() # 获取文本
html = mime_data.html() # 获取 HTML
urls = mime_data.urls() # 获取 URL 列表
image = mime_data.imageData() # 获取图像
color = mime_data.colorData() # 获取颜色
# 4. 获取所有可用的格式
formats = mime_data.formats() # 返回字符串列表
3.QMimeData 的内部结构
QMimeData 内部使用字典结构存储数据,键是 MIME 类型,值是 QByteArray:
python
class QMimeDataPrivate:
def __init__(self):
self.data = {} # {mime_type: QByteArray}
# 实际使用
mime_data = QMimeData()
mime_data.setData("text/plain", "Hello".encode('utf-8'))
mime_data.setData("text/html", "<b>Hello</b>".encode('utf-8'))
4.QMimeData 的实际应用
button_QMime.py 的例程代码:
python
import sys
import os
from PySide6.QtWidgets import *
from PySide6.QtGui import *
from PySide6.QtCore import *
class ButtonQMime(QPushButton):
def __init__(self, title=None, parent=None):
super().__init__(title, parent)
self.setAcceptDrops(True)
def dragEnterEvent(self, e):
if e.mimeData().hasFormat("text/plain"):
e.accept()
else:
e.ignore()
def dropEvent(self, e):
self.setText(e.mimeData().text())
class ButtonMyQMime(QPushButton):
def __init__(self, title=None, parent=None):
super().__init__(title, parent)
self.setAcceptDrops(True)
self.mime = QMimeData()
qb = QByteArray(bytes('abcd_wo爱中国_123', encoding='utf8'))
self.mime.setData('my_mimetype',qb)
def dragEnterEvent(self, e):
if self.mime.hasFormat('my_mimetype'):
e.accept()
else:
e.ignore()
def dropEvent(self, e):
self.setText('自定义format结果为:'+self.mime.data('my_mimetype').data().decode('utf8'))
主程序代码:
python
#QMimeData 数据传输中介
# 创建新的布局
self.grid_layout = QGridLayout(self.ui.m_widget)
self.label = QLabel('拖拽到窗口显示拖拽format信息',self)
self.grid_layout.addWidget(self.label)
self.ui.m_widget.setAcceptDrops(True)
# 图像显示标签
self.ui.lab_Show.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.ui.lab_Show.setStyleSheet("border: 2px dashed gray; padding: 10px;")
self.ui.lab_Show.setMinimumHeight(300)
def dragEnterEvent(self, e):
_str = ''
mime = e.mimeData()
# 识别拖拽的文件
if mime.hasUrls():
path_list = e.mimeData().urls()
_str = '\n'.join(a.path() for a in path_list)
_str = '拖拽的文件路径为:\n' + _str + '\n\n'
# 识别拖拽的文字
if mime.hasText():
_str = _str + '拖拽的文字内容为:\n' + mime.text() + '\n\n'
format_list = mime.formats()
self.label.setText(_str + '拖拽的formats为:\n'+'\n'.join(format_list))

①本例程主要通过 button 和 button2 分别实现了标准及自定义 QMimeData 的方法,通过 Drag 体现出来,QMimeData 在拖曳
过程中提供数据交换的通道;
②自定义了两个 QPushButton 子类,然后在 UI 界面对 QPushButton 控件分别进行提升(提升操作在第十六节有做介绍),主要用于演示 QMimeData 的标准方法和自定义数据的方式;

③在 ButtonQMime 代码中,dragEnterEvent() 函数中的 e 是 QDragEnterEvent 类型,拖曳动作进入该按钮时会触发该事件;dropEvent() 函数中的 e 是 QDropEvent 类型,拖曳动作在按钮上被释放时会触发该事件。两个 e.mimeData() 函数都是 QMimeData 类型的,存储拖曳的数据信息。该代码表示在一个拖曳操作中,QMimeData 如果判断拖曳的是文本就会接受这个拖曳操作,并且在拖曳释放的时候设置按钮的 text 为拖曳的文本;
④QMimeData 中的常见格式如果无法满足需求,则可以使用自定义的格式(mimeType),在 ButtonMyQMime 代码中新增了一个 mimeType,并把按钮的 text 修改为 mimeType 对应的数据。实现的效果是只要拖曳到按钮,按钮的 text 自动修改为 "abcd_wo爱中国_123" 。需要注意的是,setData 接收的参数的类型为 QByteArray,这是 Qt 支持的二进制格式,所以必须把数据转换成这种格式才可以通过 QMimeData 传输,这就增加了额外的工作量。实际上,对于上面的案例,也可以通过self.mime.setText(abcd_wo爱中国_123') 传递字符串,同时使用 self.mime.text()函数获取字符串;
⑤在主程序中的 dragEnterEvent 事件针对的是窗口,拖曳到窗口中时会触发,通过介绍可以大体理解 QMimeData 类型数据的保存和传输。
二、剪贴板(Clipboard)
QClipboard 提供了对系统剪贴板的访问,可以在应用程序之间复制和粘贴数据。QClipboard 的操作同样是使用 QMimeData 进行传输数据。
1.获取 QClipboard 实例
python
from PySide6.QtWidgets import QApplication
from PySide6.QtGui import QClipboard
# 获取剪贴板实例
clipboard = QApplication.clipboard()
2.基本数据类型操作
python
# 1. 文本操作
clipboard.setText("Hello, Clipboard!") # 设置文本
text = clipboard.text() # 获取文本
# 2. HTML 操作
clipboard.setHtml("<b>Bold Text</b>") # 设置HTML
html = clipboard.html() # 获取HTML
# 3. 图像操作
from PySide6.QtGui import QPixmap
pixmap = QPixmap("image.png")
clipboard.setPixmap(pixmap) # 设置图像
pixmap = clipboard.pixmap() # 获取图像
# 4. URL 操作
from PySide6.QtCore import QUrl
urls = [QUrl("file:///path/to/file"), QUrl("https://example.com")]
clipboard.setUrls(urls) # 设置URL列表
urls = clipboard.urls() # 获取URL列表
3.实践操作
python
# QClipboard 剪贴板操作
# 当前图像变量
self.current_pixmap = None
#槽函数
self.ui.text_copy_btn.clicked.connect(self.copy_text_to_clipboard)
self.ui.text_paste_btn.clicked.connect(self.paste_text_from_clipboard)
self.ui.text_clear_btn.clicked.connect(self.ui.text_edit.clear)
self.ui.image_load_btn.clicked.connect(self.load_image)
self.ui.image_copy_btn.clicked.connect(self.copy_image_to_clipboard)
self.ui.image_paste_btn.clicked.connect(self.paste_image_from_clipboard)
self.ui.image_clear_btn.clicked.connect(self.clear_image_display)
def copy_text_to_clipboard(self):
"""复制文本到剪贴板"""
text = self.ui.text_edit.toPlainText()
if text:
clipboard = QApplication.clipboard()
clipboard.setText(text)
self.statusBar().showMessage(f"已复制文本到剪贴板: {text[:30]}...", 2000)
else:
self.statusBar().showMessage("警告: 没有文本可复制", 2000)
def paste_text_from_clipboard(self):
"""从剪贴板粘贴文本"""
clipboard = QApplication.clipboard()
text = clipboard.text()
if text:
self.ui.text_edit.setText(text)
self.statusBar().showMessage(f"已从剪贴板粘贴文本: {text[:30]}...", 2000)
else:
self.statusBar().showMessage("警告: 剪贴板中没有文本", 2000)
def load_image(self):
"""加载图像"""
file_path, _ = QFileDialog.getOpenFileName(self, "选择图像文件","","图像文件 (*.png *.jpg *.jpeg *.bmp *.gif *.webp)")
if file_path:
pixmap = QPixmap(file_path)
if not pixmap.isNull():
self.current_pixmap = pixmap
# 缩放图像以适应标签
scaled_pixmap = pixmap.scaled(
self.ui.lab_Show.size(),
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation
)
self.ui.lab_Show.setPixmap(scaled_pixmap)
self.ui.lab_Show.setText("")
self.statusBar().showMessage(f"已加载图像: {file_path}", 2000)
else:
QMessageBox.warning(self, "错误", "无法加载图像文件")
def copy_image_to_clipboard(self):
"""复制图像到剪贴板"""
if self.current_pixmap:
# 复制到剪贴板
clipboard = QApplication.clipboard()
clipboard.setPixmap(self.current_pixmap)
self.statusBar().showMessage("已复制示例图像到剪贴板", 2000)
else:
QMessageBox.warning(self, "错误", "没有图像显示,无法复制图像文件到剪贴板!")
def paste_image_from_clipboard(self):
"""从剪贴板粘贴图像"""
clipboard = QApplication.clipboard()
if clipboard.mimeData().hasImage():
image = clipboard.image()
if not image.isNull():
self.current_pixmap = QPixmap.fromImage(image)
self.ui.lab_Show.setPixmap(self.current_pixmap.scaled(
self.ui.lab_Show.size(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation
))
self.ui.lab_Show.setText("")
self.statusBar().showMessage("已从剪贴板粘贴图像", 2000)
else:
self.statusBar().showMessage("错误: 剪贴板中的图像无效", 2000)
else:
self.statusBar().showMessage("警告: 剪贴板中没有图像", 2000)
def clear_image_display(self):
"""清空图像显示"""
self.ui.lab_Show.clear()
self.ui.lab_Show.setText("图像将显示在这里")
self.current_pixmap = None
self.statusBar().showMessage("已清空图像显示", 2000)

①QClipboard 是 PySide6 中用于访问系统剪贴板的类,支持文本、图像、HTML等多种格式的数据传输。上述例程只介绍了文本和图像的基本相关操作;
②通过 QApplication.clipboard() 获取剪贴板实例,clipboard.setText(text) 复制文本到剪贴板;text = clipboard.text() 从剪贴板粘贴文本;
③通过 clipboard.setPixmap(self.current_pixmap) 复制图像到剪贴板;通过 clipboard.mimeData().hasImage() 判断剪粘板上是否有图像数据,然后 image = clipboard.image() 从剪贴板上获取图像。
注意点:
①在实际应用中发现,为什么无法在文件夹复制图像,然后粘贴到程序中?
根本原因:从文件夹复制图像文件通常不是复制图像数据本身,而是复制文件路径,这需要处理不同的MIME类型。所以可以通过解析复制的路径对图像进行加载显示,这里可以探索实操下;
②为什么不能与其他程序共享剪贴板图像?
这个问题很常见,通常是由于以下原因导致的:
1、MIME类型不匹配:不同程序使用不同的剪IME类型来存储图像数据;
2、图像格式限制:某些程序只支持特定格式的图像剪贴板数据;
3、平台差异:Windows、macOS和Linux处理剪贴板图像的方式不;
4、Qt内部格式:QClipboard默认使用Qt特定的内部格式;
总结
QMimeData 的核心特性
| 特性 | 说明 |
|---|---|
| 多格式支持 | 同时存储多种格式的数据 |
| 平台兼容 | 在不同平台间保持一致的 MIME 类型 |
| 数据封装 | 将原始数据封装为标准格式 |
| 类型检查 | 提供方便的格式检查方法 |
| 数据转换 | 支持格式间的自动转换 |
后续会专门详细介绍 Drag 与 Drop 功能,该功能比 Clipboard 功能更常用,也更重要。