在 Qt 中,QClipboard 类提供了相关 API 让应用程序具备读/写剪贴板的能力。数据通过 QMimeData 类包装。该类使用 MIME 类型来标识数据。比如,要包装的数据是纯文本内容,就使用 text/plain;如果是 PNG 图像数据,就用 image/png。当然,自定义类型也是可以的,如 application/xxx。
void setData(const QString &mimetype, const QByteArray &data;
mimetype 参数为字符串,指定数据的 MIME 类型;data 参数就是数据本尊,类型为字节序列。通过 setData 方法的签名,咱们也能知道,QMimeData 类可以放任意内容。要获取数据时,data 方法需要通过 MIME 类型来检索。
文本 | 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 用来显示文本;然后是两个按钮—— 执行“复制”和“粘贴”操作。
构造函数的实现比较简单,就是调用 _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 类也是一个组件,以网格方式布局各组件。网格的行和列是自动划分的。上面代码中其实用到了三列两行:
2、第二列空着,没放东西;
4、“复制”按钮在第一列第二行;
这三行是设定空间比例的。
_layout->setColumnStretch(0, 2; _layout->setColumnStretch(1, 1; _layout->setColumnStretch(2, 2;
这意思就是,列的总宽平均分为4份,第一列和第三列都占两份,第二列只占一份。
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(; }
运行程序,先输入一些文本,点击“复制”;再点击“粘贴”,被复制的文本就会显示出来了。
1、text、setText:设置或获取文本;
3、setPixmap 和 pixmap:设置或获取图像(QPixmap类型)。
对于图像数据的复制和粘贴,操作流程差不多,大伙伴有兴趣可以试试。
前文提到过,除了常见的数据格式外,QMimeData 允许自定义格式,用 MIME 来标识。
以下是自定义窗口类的头文件定义。
#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> 元素差不多,即表单。
第一个是 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生动形象地描述出数据的流动方向。注意输入和输出时,数据的顺序必须一致。
1、创建 QByteArray 实例;
3、创建 QDataStream 实例,关联 QBuffer 实例。
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; }
反序列化的原理与序列化是一样的,只是反向操作罢了。注意读写数据的顺序,写的时候是姓名 - 生日 - 祝福语,读的时候也必须按这个顺序。
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
重点就是三步:
2、auto moc 一定要打开,否则编译时会挂。
先运行一个程序实例,输入相关信息,点复制按钮。