剪贴板是个啥就不用多介绍了,最直观的功能是实现应用程序之间数据共享。就是咱们常说的“复制”、“粘贴”功能。

在 Qt 中,QClipboard 类提供了相关 API 让应用程序具备读/写剪贴板的能力。数据通过 QMimeData 类包装。该类使用 MIME 类型来标识数据。比如,要包装的数据是纯文本内容,就使用 text/plain;如果是 PNG 图像数据,就用 image/png。当然,自定义类型也是可以的,如 application/xxx。

QMimeData 的核心方法是 setData 和 data。setData 方法用来放入数据,data 方法用来取出数据。setData 方法的签名如下:

void setData(const QString &mimetype, const QByteArray &data);

mimetype 参数为字符串,指定数据的 MIME 类型;data 参数就是数据本尊,类型为字节序列。通过 setData 方法的签名,咱们也能知道,QMimeData 类可以放任意内容。要获取数据时,data 方法需要通过 MIME 类型来检索。

为了便于存取常见的数据——如文本、图像、HTML文本等,QMimeData 类提供一些封装好的方法成员:

文本 setText 设置普通文本
text 获取普通文本
hasText
判断是否存在文本数据
HTML文本
setHtml
设置 HTML 文本
html
获取HTML文本
hasHtml
判断是否存在 HTML 文本数据
URL
setUrls
设置 URL 列表,参数为 QList<QUrl>
urls 获取 URL 列表
hasUrls
检测是否存在 URL 列表
图像
setImageData
设置图像数据
imageData
获取图像数据
hasImage
判断是否存在图像数据
颜色
setColorData
设置颜色数据
colorData
获取颜色数据
hasColor
是否存在颜色数据

QClipboard 类不能直接实例化使用,它由 QGuiApplication 类的静态成员 clipboard 公开。该静态成员返回 QClipboard 类的指针,程序代码将通过这个指针来访问 QClipboard 对象。由于 QApplication 类派生自 QGuiApplication,当然也继承了 clipboard 成员。

下面做一个简单的练习:复制和粘贴文本。

MyWindow 类的头文件。

class MyWindow : public QWidget
{ Q_OBJECT public:
MyWindow(QWidget* parent = nullptr);
~MyWindow();
private:
void _initUi(); // 私有方法
// 下面是私有字段
QLineEdit* _txtInput;
QLabel* _lbTxt;
QPushButton* _btnCopy;
QPushButton* _btnPaste;
// 用来布局控件的
QGridLayout* _layout;
// 下面成员响应 clicked 信号
void onCopy();
void onPaste();
};

_initUi 方法负责初始化窗口上的东西。这个窗口有四个组件:一个 QLineEdit 用来输入文本;一个 QLabel 用来显示文本;然后是两个按钮—— 执行“复制”和“粘贴”操作。

后面两个方法 onCopy 和 onPaste 分别与两个按钮的 clicked 信号绑定。

构造函数的实现比较简单,就是调用  _initUi 方法。

MyWindow::MyWindow(QWidget* parent)
: QWidget::QWidget(parent)
{
// 初始化UI
this -> _initUi();
} MyWindow::~MyWindow()
{
}

析构函数这里啥也不做。

下面是 _intUi 的实现代码。

void MyWindow::_initUi()
{
// 设置一下窗口
this->setWindowTitle("复制粘贴文本");
this->setGeometry(560, 480, 320, 150);
this->setMinimumSize(300, 150); _txtInput = new QLineEdit();
_lbTxt = new QLabel();
_btnCopy = new QPushButton("复制");
_btnPaste = new QPushButton("粘贴");
_layout = new QGridLayout(this);
// 设置空白
_layout->setSpacing(12);
// 放置各控件
_layout->addWidget(_txtInput, 0, 0);
_layout->addWidget(_btnCopy, 1, 0);
_layout->addWidget(_lbTxt, 0, 2);
_layout->addWidget(_btnPaste, 1, 2);
_layout->setColumnStretch(0, 2);
_layout->setColumnStretch(1, 1);
_layout->setColumnStretch(2, 2); // 绑定信号和槽
connect(_btnCopy, &QPushButton::clicked, this, &MyWindow::onCopy);
connect(_btnPaste, &QPushButton::clicked, this, &MyWindow::onPaste);
}

QGridLayout 类也是一个组件,以网格方式布局各组件。网格的行和列是自动划分的。上面代码中其实用到了三列两行:

1、QLineEdit 在第一列第一行;

2、第二列空着,没放东西;

3、 QLabel 组件在第三列第一行;

4、“复制”按钮在第一列第二行;

5、“粘贴”按钮在第二行第二行。

这三行是设定空间比例的。

    _layout->setColumnStretch(0, 2);
_layout->setColumnStretch(1, 1);
_layout->setColumnStretch(2, 2);

这意思就是,列的总宽平均分为4份,第一列和第三列都占两份,第二列只占一份。

随后是与 clicked 信号绑定的两个私有方法。

void MyWindow::onCopy()
{
// 获得 QClipboard 的引用
QClipboard* clboard = QApplication::clipboard();
// 设置文本数据
clboard -> setText(_txtInput -> text());
} void MyWindow::onPaste()
{
// 过程差不多
QClipboard* cb = QApplication::clipboard();
QString s = cb->text();
// 显示粘贴的文本
_lbTxt->setText(s);
}

最后是 main 函数的代码:

int main(int argc, char** argv)
{
QApplication app(argc, argv);
MyWindow win;
win.show();
return app.exec();
}

运行程序,先输入一些文本,点击“复制”;再点击“粘贴”,被复制的文本就会显示出来了。

这个例子用了 QClipboard 类公开的封装方法,不需要操作 QMimeData 类。针对常用的数据格式,可直接用。

1、text、setText:设置或获取文本;

2、setImage 和 image:设置或获取图像(QImage类型);

3、setPixmap 和 pixmap:设置或获取图像(QPixmap类型)。

后面两个是读写图像的。

对于图像数据的复制和粘贴,操作流程差不多,大伙伴有兴趣可以试试。

前文提到过,除了常见的数据格式外,QMimeData 允许自定义格式,用 MIME 来标识。

接下来,咱们做个练习,复制和粘贴生日贺卡信息。假设生日贺卡信息包括姓名、生日、祝福语。咱们用自定义的数据格式将其复制,也可以粘贴到应用程序上。MIME 类型为 application/bug。

以下是自定义窗口类的头文件定义。

#ifndef APP_H
#define APP_H
#include <qwidget.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qdatetimeedit.h> class CustWind : public QWidget
{
Q_OBJECT
public:
CustWind(QWidget* parent = nullptr);
private:
QLineEdit* txtName;
QLineEdit* txtWish;
QDateEdit* txtDate;
QPushButton* btnCopy;
QPushButton* btnPaste; // 与 clicked 信号绑定的方法(Slots)
void onCopy();
void onPaste();
}; #endif

在包含头文件时,用带 .h 后缀和不用后是一样的,既可以用 <QWidget> 也可以用 <qwidget.h>,只是作兼容之用。

在构造函数中,初始化各类可视对象。

CustWind::CustWind(QWidget *parent)
: QWidget::QWidget(parent)
{
// 初始化组件
txtName = new QLineEdit();
txtWish = new QLineEdit();
txtDate = new QDateEdit();
// 有效日期范围
txtDate -> setMinimumDate(QDate(1950, 1, 1));
txtDate -> setMaximumDate(QDate(2085, 12, 31));
btnCopy = new QPushButton("复制生日贺卡");
btnPaste = new QPushButton("粘贴生日贺卡");
// 布局
QFormLayout* layout = new QFormLayout(this);
layout->addRow("姓名:", txtName);
layout->addRow("生日:", txtDate);
layout->addRow("祝福语:", txtWish);
QVBoxLayout *sublayout = new QVBoxLayout();
sublayout->addWidget(btnCopy);
sublayout->addWidget(btnPaste);
layout ->addRow(sublayout);
// 连接信号和槽
connect(btnCopy,&QPushButton::clicked,this,&CustWind::onCopy);
connect(btnPaste,&QPushButton::clicked,this,&CustWind::onPaste);
}

这个例子咱们用 QFormLayout 来布局界面。其含义和 HTML 中 <form> 元素差不多,即表单。

下面重点说两个 slot 方法。

第一个是 onCopy ,由复制按钮的点击触发。

void CustWind::onCopy()
{
// 获取数据
QString name = txtName->text();
QString wish = txtWish->text();
QDate birthdate = txtDate->date();
if(name.isEmpty())
{
return; //姓名是空的
}
// 开始序列化
QByteArray data;
QBuffer buff(&data);
// buffer 要先打开
buff.open(QBuffer::WriteOnly);
QDataStream output(&buff);
// 写入数据
output << name << birthdate << wish;
buff.close();
// 包装数据
QMimeData packet;
packet.setData("application/bug", data);
// 把数据放到剪贴板
QClipboard* cb = QApplication::clipboard();
cb->setMimeData(&packet); QMessageBox::information(this,"恭喜","生日贺卡复制成功",QMessageBox::Ok);
}

Qt 里面常用 QDataStream 类来做序列化和反序列化操作。由于它有运算符重载,我们可以使用 C++ 入门时最熟悉的 <<、>> 运算符来输入输出。向 QDataStream 对象写入数据时:

dataStream << a << b << c;

反序列化时:

dataStream >> a >> b >> c;

运算符很TM生动形象地描述出数据的流动方向。注意输入和输出时,数据的顺序必须一致。

QMimeData 类用 setData 方法设置自定义数据时,参数接收的类型是 QByteArray(字节数组)而不是 QDataStream 对象,因此,我们要用 QBuffer 类来中转一下。

1、创建  QByteArray 实例;

2、创建  QBuffer 实例,关联 QByteArray 实例;

3、创建  QDataStream 实例,关联 QBuffer 实例。

QDataStream 类需要 QIODevice 的派生类来完成读写操作,而 QByteArray 类不是 QIODevice 的子类,故要用 QBuffer 来过渡一下。当然了,老周这里为了让这个思路更清晰一些,所以“中规中矩”地写代码。其实,QDataStream 类有接收 QByteArray 类型的参数的,可以省略 QBuffer 的代码。QDataStream 类内部自动创建 QBuffer 对象。

第二个 slot 方法是 onPaste,实现贺卡的粘贴。

void CustWind::onPaste()
{
// 访问剪贴板
QClipboard* cb=QApplication::clipboard();
const QMimeData* dataPack = cb->mimeData();
// 判断一下有没有我们要的数据
if(!dataPack->hasFormat("application/bug"))
{
return;
}
// 取出数据
QByteArray data = dataPack->data("application/bug");
// 反序列化
QBuffer buff(&data);
// 记得先打开 buffer
buff.open(QBuffer::ReadOnly);
QDataStream input(&buff);
// 注意读的顺序
QString name;
QDate birth;
QString wish;
input >> name >> birth >> wish;
// 显示数据
this->txtName->setText(name);
this->txtDate->setDate(birth);
this->txtWish->setText(wish);
}

反序列化的原理与序列化是一样的,只是反向操作罢了。注意读写数据的顺序,写的时候是姓名 - 生日 - 祝福语,读的时候也必须按这个顺序。

最后,是 main 函数。

int main(int argc, char* argv[])
{
QApplication myapp(argc, argv);
CustWind mwindow;
mwindow.show();
return myapp.exec();
}

CMake 文件(CMakeLists.txt)就按照标准文档上直接抄就行了。

cmake_minimum_required(VERSION 3.20)
project(demo LANGUAGES CXX)
find_package(
Qt6
REQUIRED COMPONENTS
Core
Gui
Widgets
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
add_executable(demo app.h app.cpp)
target_link_libraries(
demo
PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)

重点就是三步:

1、声明 CMake 文档支持的版本,应用项目的名称(target)。

2、auto moc 一定要打开,否则编译时会挂。

3、添加源代码、链接相关的库。

好了,完工了,咱们试试。

先运行一个程序实例,输入相关信息,点复制按钮。

然后,关闭这个程序重新运行,或者再运行一个新程序实例,点粘贴按钮。

这样,就完成了自定义数据的复制和粘贴。

【Qt 6】读写剪贴板的更多相关文章

  1. python3 使用pyperclip读写剪贴板(windows)

    2016年5月14日 03:41:38 codegay 使用pyperclip库读写剪贴板非常简单~, 1.使用命令安装: pip install pyperclip 2.然后...就可以了: 以下是 ...

  2. Qt 二进制文件读写(使用“魔术数字”)

    今天开始进入 Qt 的另一个部分:文件读写,也就是 IO.文件读写在很多应用程序中都是需要的.Qt 通过 QIODevice 提供了IO的抽象,这种设备(device)具有读写字节块的能力.常用的IO ...

  3. QT QSettings读写配置文件

    QT QSettings读写配置文件 需要用一个配置文件来保存程序的初始值,同时也需要做保存修改后的值. 那么借助于QSetting 就可以达到目的. 注意,生成的是 ini 文件! //1.创建和读 ...

  4. 【WP开发】读写剪贴板

    在WP 8.1中只有Silverlight App支持操作剪贴板的API,Runtime App并不支持.不过,在WP 10中也引入了可以操作剪贴板的API. 顺便说点题外话,有人会说,我8.1的开发 ...

  5. Qt文本读写之一:输入输出设备和文件操作

    一.输入输出设备 QIODevice类是Qt中所有I/O设备的基础接口类,为诸如QFile.QBuffer和 QTcpSocket等支持读/写数据块的设备提供了一个抽象接口.QIODevice类是抽象 ...

  6. Qt文件读写操作

    原文地址:https://www.cnblogs.com/flowingwind/p/8336159.html QFile Class 1.read读文件 加载文件对象  QFile file(&qu ...

  7. 一篇文章快速搞懂Qt文件读写操作

    导读:Qt当中使用QFile类对文件进行读写操作,对文本文件也可以与QTextStream一起使用,这样读写操作会更加简便.QFileInfo可以用来获取文件的信息.QDir可以用于对文件夹进行操作. ...

  8. Qt文本读写之二:目录操作

    一.简介 QDir类用来访问目录结构及其内容,可以操作路径名.访问路径和文件相关信息以及操作底层的文件系统,还可以访问Qt的资源系统.Qt使用"/"作为通用的目录分隔符和URLs的 ...

  9. QT文件读写操作笔记

    补一下这部分的笔记 简单的东西也记一下 操作系统一般都会提供一些列的标准对话框,如文件选择.字体选择.颜色选择等,这些标准对话框为应用层序提供了一致的观感.Qt对这些标准对话框都定义了相关的类,如:Q ...

  10. [Qt] 文本文件读写, 摘自官方文档

    Reading Files Directly The following example reads a text file line by line: QFile file("in.txt ...

随机推荐

  1. Glist 按钮属性

    grayed 变灰与否不影响点击等事件 touchable 为false,不会变灰,但会无法点击, enabled为false自动变灰,且无法点击

  2. luffy项目settings

    一:  二:. 设置调整 1.修改manage.py配置路径 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffyApi.settings.de ...

  3. Thingsboard3.2.2本地部署

    Thingboard3.2.2本地安装编译详细教程!!! 一:拉取源码. 创建一个空的文件夹 在此处使用git拉取源码. git clone https://github.com/thingsboar ...

  4. 11.7 消除闪烁(1)(harib08g)

    ps:看书比较急,有错误的地方欢迎指正,不细致的地方我会持续的修改 11.7 消除闪烁(1)(harib08g) 11.6 高速计数器(harib08f)存在闪烁的问题,产生原因:刷新时会从低到高进行 ...

  5. MD5 简介 以及 C# 和 js 实现【加密知多少系列】

    〇.简介 MD5 是哈希算法(散列算法)的一种应用.Hash 算法虽然被称为算法,但实际上它更像是一种思想.Hash 算法没有一个固定的公式,只要符合散列思想的算法都可以被称为是 Hash 算法. 算 ...

  6. PGF 概率生成函数 Probability generating function

    Probability Mass Function 离散随机变量的分布函数PMF 目录 随机结构举例 two classical combinatorial distributions PGF Pro ...

  7. 自己动手从零写桌面操作系统GrapeOS系列教程——18.外设和IO

    学习操作系统原理最好的方法是自己写一个简单的操作系统. 一.外设和I/O接口 前面我们介绍过冯·诺依曼结构包含5部分,其中输入设备和输出设备统称为外部设备,简称外设.常见的外设有鼠标.键盘.显示器.硬 ...

  8. Logoist - 适用于设计师以及初次使用者的快速制作精美 logo 工具

    ![在这里插入图片描述](https://img-blog.csdnimg.cn/24c0f566dcf14be2aa72afaa78c87c40.png)>从简单的标识到设计开发.它只需要一点 ...

  9. 基于Label studio实现UIE信息抽取智能标注方案,提升标注效率!

    基于Label studio实现UIE信息抽取智能标注方案,提升标注效率! 项目链接见文末 人工标注的缺点主要有以下几点: 产能低:人工标注需要大量的人力物力投入,且标注速度慢,产能低,无法满足大规模 ...

  10. [Linux]常用命令之【diff】

    1 概述 2 diff命令 diff 命令是 Linux 上比较重要的命令行工具,用于比较文本内容,并找到不相同的地方,diff 在命令行中打印每一行的改动之处. diff 程序的输出被称为补丁(pa ...