15.1 输入/输出设备
- QIODevice类是Qt中所有I/O设备的基础接口类,为诸如QFile、QBuffer和QTcpSocket等支持读写数据块的设备提供了一个抽象接口。QIODevice类是抽象的,无法被实例化,一般是使用它所定义的接口来提供设备无关的I/O功能。
- 在访问一个设备以前,需要使用open()函数打开该设备,而且必须指定正确的打开模式。QIODevice中所有的打开模式由QIODeviceBase::OpenMode枚举类型定义,其取值如表所列,其中的一些值可以使用按位或符号"|"来同时使用。打开设备后可以使用write()或者putChar()来进行写入,使用read()、readLine()或者readAll()进行读取,最后使用close()关闭设备。

- QIODevice会区别两种类型的设备:随机存取设备和顺序存取设备。随机存取设备支持使用seek()函数来定位到任意的位置。文件中的当前位置可以使用pos()函数来获取。这样的设备有QFile、QBuffer等。顺序存取设备不支持定位到任意的位置,数据必须一次性读取。pos()和size()等函数无法在操作顺序设备时使用。这样的设备有QTcpSocket、QProcess等。
15.2 文件操作
15.2.1 QFile
- QFile类提供了一个用于读写文件的接口,它是一个可以用来读写文本文件、二进制文件和Qt资源的I/O设备。QFile可以单独使用,也可以和QTextStream或者QDataStream一起使用,这样会更方便。
- 一般在构建QFile对象时便指定文件名,当然也可以使用setFileName()进行设置。无论在哪种操作系统上,文件名路径中的文件分隔符都需要使用'/'符号。可以使用exists()来检查文件是否存在,remove()来删除一个文件。更多与文件系统相关的高级操作在QFileInfo和QDir类中提供。
- 一个文件可以使用open()打开,使用close()关闭,使用flush()刷新。文件的数据读写一般使用QDataStream或者QTextStream来完成,不过也可以使用继承自QIODevice类的一些函数,比如read()、readLine()、readAll()和write(),还有一次只操作一个字符的getChar()、putChar()和ungetChar()等函数。可以使用size()函数来获取文件的大小,使用seek()来定位到文件的任意位置,使用pos()来获取当前的位置,使用atEnd()来判断是否到达了文件的末尾。
15.2.2 QFileInfo
- QFileInfo类提供了与系统无关的文件信息,包括文件的名称、在文件系统中的位置(路径)、文件的访问权限以及是否是一个目录或者符号链接等。
- QFileInfo可以使用相对(relative)路径或者绝对(absolute)路径来指向一个文件,还可以使用makeAbsolute()来将一个相对路径转换为绝对路径。QFileInfo指向的文件可以在QFileInfo对象构建时设置,或者在以后使用setFile()来设置。可以使用exists()来查看文件是否存在,使用size()可以获取文件的大小。文件的类型可以使用isFile()、isDir()和isSymLink()来获取,symLinkTarget()函数可以返回符号链接指向的文件的名称。
- 可以分别使用path()和fileName()来获取文件的路径和文件名,还可以使用baseName()来获取文件名中的基本名称,使用suffix()来获取文件名的后缀,使用completeSuffix()来获取复合后缀。文件的日期可以使用birthTime()、lastModified()、lastRead()和fileTime()来返回;访问权限可以使用isReadable()、isWritable()和isExecutable()来获取;文件的所有权可以使用owner()、ownerId()、group()和groupId()来获取。
15.2.3 QTemporaryFile
- QTemporaryFile类是一个用来操作临时文件的I/O设备,它可以安全地创建一个唯一的临时文件。当调用open()函数时便会创建一个临时文件,临时文件的文件名可以保证是唯一的,当销毁QTemporaryFile对象时,该文件会被自动删除掉。在调用open()函数时,默认会使用QIODevice::ReadWrite模式,可以像下面的代码这样来使用QTemporaryFile类:
cpp
QTemporaryFile file;
if (file.open()) {
// 在这里对临时文件进行操作,file.fileName()可以返回唯一的文件名
}
- 在调用了close()函数后重新打开QTemporaryFile是安全的,只要QTemporaryFile的对象没有被销毁,那么唯一的临时文件就会一直存在而且由QTemporaryFile内部保持打开。临时文件默认会生成在系统的临时目录里,这个目录的路径可以使用QDir::tempPath()来获取。
15.3 目录操作
15.3.1 QDir
- QDir类用来访问目录结构及其内容,可以操作路径名、访问路径和文件相关信息以及操作底层的文件系统,还可以访问Qt的资源系统。Qt使用"/"作为通用的目录分隔符和URLs的目录分隔符,如果使用"/"作为目录分隔符,Qt会自动转换路径来适应底层的操作系统。QDir可以使用相对路径或者绝对路径来指向一个文件,使用绝对路径的例子:
cpp
QDir("/home/user/Documents")
QDir("C:/Documents and Settings")
- 可以使用isRelative()和isAbsolute()来判断一个QDir是否使用了相对路径或者绝对路径。一个目录的路径可以使用path()函数获取,使用setPath()函数可以设置新的路径,使用absolutePath()函数可以获取绝对路径。目录名可以使用dirName()函数获取,如果QDir代表当前目录,那么会返回"."。目录的路径也可以使用cd()和cdUp()函数来改变,当使用一个存在的目录的名字来调用cd()后,QDir对象就会转换到指定的目录;而cdUp()会跳转到父目录。可以使用mkdir()来创建目录,使用rename()进行重命名,使用rmdir()删除目录。
- 可以应用一个名称过滤器(name filters)来使用通配符(wildcards)指定一个模式进行文件名的匹配,一个属性过滤器可以选取条目的属性并且可以区分文件和目录,还可以设定排序顺序。名称过滤器就是一个字符串列表,可以使用setNameFilters()函数来设置,例如下面的代码在QDir上使用了三个名称过滤器来确保只有以通常用于C++源文件的扩展名结尾的文件才会被列出:
cpp
QStringList filters;
filters << "*.cpp" << "*.cxx" << "*.cc";
dir.setNameFilters(filters);
- 属性过滤器由按位或组合在一起的过滤器组成,可以使用setFilter()来进行设置。排序顺序使用setSorting()来设置,它需要指定按位或组合在一起的排序标志QDir::SortFlags,所有的排序标志可以在QDir的帮助文档中进行查看,包含了按名称、按时间、按大小等排序方式。
- 要访问一些常见的目录,可以使用一些静态函数来完成,它们可以返回QDir对象或者QString类型的绝对路径,这些函数如表所列。

15.3.2 文件系统监视器QFileSystemWatcher
- QFileSystemWatcher类提供了一个接口用来监控文件和目录的修改,通过监视一个指定路径的列表来监控文件系统中文件和目录的改变。调用addPath()来监视一个指定的文件或者目录,多个路径可以使用addPaths()函数来添加,现有的路径可以使用removePath()和removePaths()函数来移除。
- QFileSystemWatcher会检测每一个添加到它上面的路径,添加到其上的文件的路径可以使用files()来获取,目录的路径可以使用directories()函数来获取。
- 当文件被修改、重命名或者移除后,会发射fileChanged()信号,相似的,当目录或者它的内容被修改或者移除后,会发射directoryChanged()信号。需要注意的是,当文件被重命名或者移除后,或者当目录被移除后,QFileSystemWatcher都会停止监视。
cpp
// 将监视器的信号和自定义的槽进行关联
connect(&myWatcher, &QFileSystemWatcher::directoryChanged,this, &MainWindow::showMessage);
connect(&myWatcher, &QFileSystemWatcher::fileChanged,this, &MainWindow::showMessage);
// 显示出当前目录下的所有.h文件
QDir myDir(QDir::currentPath());
myDir.setNameFilters(QStringList("*.h"));
ui->listWidget->addItem(myDir.absolutePath() + tr("目录下的.h文件有:"));
ui->listWidget->addItems(myDir.entryList());
// 创建目录,并将其加入到监视器中
myDir.mkdir("mydir");
myDir.cd("mydir");
ui->listWidget->addItem(tr("监视的目录:") + myDir.absolutePath());
myWatcher.addPath(myDir.absolutePath());
// 创建文件,并将其加入到监视器中
QFile file(myDir.absolutePath() + "/myfile.txt");
if (file.open(QIODevice::WriteOnly)) {
QFileInfo info(file);
ui->listWidget->addItem(tr("监视的文件:") + info.absoluteFilePath());
myWatcher.addPath(info.absoluteFilePath());
file.close();
}
cpp
// 显示文件或目录改变信息
void MainWindow::showMessage(const QString &path)
{
QDir dir(QDir::currentPath() + "/mydir");
// 如果是目录发生了改变
if (path == dir.absolutePath()) {
ui->listWidget->addItem(dir.dirName() + tr("目录发生改变: "));
ui->listWidget->addItems(dir.entryList());
} else { // 如果是文件发生了改变
ui->listWidget->addItem(path + tr("文件发生改变!"));
}
}
15.4 文本流和数据流
15.4.1 文本流
- QTextStream类提供了一个方便的接口来读/写文本,可以在QIODevice、QByteArray和QString上进行操作。使用QTextStream的流操作符,可以方便地读/写单词、行和数字。对于生成文本,QTextStream对字段填充、对齐和数字格式提供了格式选项支持。例如:
cpp
QFile data("output.txt");
if (data.open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream out(&data);
// 写入 "Result: 3.14 2.7 "
out << "Result: " << qSetFieldWidth(10) << left << 3.14 << 2.7;
}
- 在内部,QTextStream使用了一个基于Unicode的缓冲区,QTextStream使用QStringConverter来自动支持不同的编码。默认的,使用UTF-8来进行读写,也可以使用setEncoding()函数来设置编码。
- 使用QTextStream来读取文本文件一般使用三种方式:
1)调用readLine()或者readAll()进行一块接着一块的读取;
2)一个单词接着一个单词。QTextStream支持流入到QString、QByteArray和char*缓冲区,单词由空格分开,而且可以自动跳过前导空格;
3)一个字符接着一个字符,使用QChar或者char类型的流。这种方式经常在解析文件、使用独立的字符编码和行结束语义时用于方便输入处理。可以通过调用skipWhiteSpace()来跳过空格。
15.4.2 数据流
- QDataStream类实现了将QIODevice的二进制数据串行化。一个数据流就是一个二进制编码信息流,数据流也可以读/写未编码的原始二进制数据。QDataStream类可以实现C++基本数据类型的串行化,比如char、short、int和char*等。
- 将二进制数据写入到数据流中:
cpp
QFile file("file.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file); // 要将串行化后的数据输入到file中
out << QString("the answer is"); // 串行化字符串
out << (qint32)42; // 串行化整数
- 从数据流中读取二进制数据:
cpp
QFile file("file.dat");
file.open(QIODevice::ReadOnly);
QDataStream in(&file); // 从file中读取串行化的数据
QString str;
qint32 a;
in >> str >> a; // 提取"the answer is"和42
- 从Qt 1.0开始便有了相应的QDataStream的二进制格式,而且它会继续发展来反映Qt中的变化。当输入或输出复杂数据类型时,确保使用相同的数据流版本(version())来进行读取和写入是非常重要的。对于基本的C++数据类型没有这个要求。如果既要实现向前兼容,又要实现向后兼容,可以在应用程序中对数据流的版本号进行硬编码:
cpp
stream.setVersion(QDataStream::Qt_4_0);
- 如果要使用一个新的二进制数据格式,例如在自己应用程序中创建的一个文档的文件格式,这就需要在数据流的前面写入一个简短的数据头,包含了一个magic number(幻数或魔数,用来标志文件格式的常数)和一个版本号。例如:
cpp
QFile file("file.xxx");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out << (quint32)0xA0B0C0D0; // 写入幻数和版本号
out << (qint32)123;
out.setVersion(QDataStream::Qt_4_0);
out << lots_of_interesting_data; // 写入数据
- 这里幻数可以是一个自定义数字,它是32位的。下面来读取该数据流:
cpp
QFile file("file.xxx");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
// 读取幻数
quint32 magic;
in >> magic;
if (magic != 0xA0B0C0D0) return XXX_BAD_FILE_FORMAT;
// 读取版本
qint32 version;
in >> version;
if (version < 100) return XXX_BAD_FILE_TOO_OLD;
if (version > 123) return XXX_BAD_FILE_TOO_NEW;
if (version <= 110) in.setVersion(QDataStream::Qt_3_2);
else in.setVersion(QDataStream::Qt_4_0);
// 读取数据
in >> lots_of_interesting_data;
if (version >= 120) in >> data_new_in_XXX_version_1_2;
in >> other_interesting_data;
15.5 其他相关类
15.5.1 QSettings
- QSettings类提供了持久的与平台无关的应用程序设置。用户通常期望应用程序可以记住它们的设置,比如窗口大小和位置等。这些信息在Windows上一般被存储在系统注册表中;在Mac OS X上存储在属性列表文件中;在Unix系统中,大多数应用程序使用INI文本文件。
- QSettings是对这些技术的一个抽象,可以使用一种可移植的方式来保存和恢复应用程序的设置。它也支持自定义存储类型。
- QSettings的API是基于QVariant的,可以用来保存大多数的基于值的类型,如QString、QRect和QImage等。
15.5.2 QUrl
- QUrl类提供了一个方便的接口来操作URLs,URL是Uniform Resource Locator的缩写,被称为统一资源定位符或者网页网址。一个URL的标准格式如下:protocol 😕/ hostname[:port] / path / [?query]#fragment
- QUrl可以解析和构建编码或者未编码格式的URLs,它也支持国际化域名(IDNs)。可以在构造函数中传递一个QString来初始化QUrl,或者使用setUrl(),URLs可以被表示为两种格式:编码和未编码。一个URL也可以被一部分一部分的进行构造,可以使用setScheme()来设置协议;使用setUserName()来设置用户名;使用setPassword()来设置密码;使用setHost()来设置主机;使用setPort()来设置端口;使用setPath()来设置路径;使用setFragment()来设置片断。还可以使用一些方便的函数来进行设置,如setAuthority()可以一次性设置用户名、密码、主机和端口;setUserInfo()可以一次性设置用户名和密码。
15.5.3 QResource
- QResource类提供了接口来直接读取资源文件。QResource是用来表示一组数据的对象,该组数据涉及了一个单一的资源实体。
- QResource可以使用原始的格式来直接访问字节,这种直接访问允许不使用缓冲拷贝。QResource背后的数据和它的孩子通常被编译成一个应用程序库,也可以在运行时加载一个资源,当在运行时进行加载时,资源文件会作为一个很大的数据集进行加载,然后通过引用资源树进行分块输出。
- QResource也可以使用一个绝对路径进行加载,绝对路径可以使用文件系统的表示法,以一个"/"字符开始,或者使用资源表示法,以":"字符开始。QResource代表的文件中的数据可以使用qCompress()来进行压缩,对应的使用qUncompress()来进行解压缩。
- 一个资源可以留在一个应用程序的二进制文件外面,等在运行需要时再使用registerResource()进行加载,传递给registerResource()的资源文件必须是rcc生成的二进制资源。
15.6 富文本
富文本(Rich Text)或者叫做富文本格式,简单来说就是在文档中可以使用多种格式,比如字体颜色、图片和表格等等。它是与纯文本(Plain Text)相对而言的,比如Windows上的记事本就是纯文本编辑器,而Word就是富文本编辑器。
15.6.1 富文本文档结构
- Qt中对富文本的处理分为编辑操作和只读操作两种方式。
1)编辑操作是使用基于光标的一些接口函数,这样更好的模拟了用户的编辑操作,更加容易理解,而且不会丢失底层的文档框架;
2)而对于文档结构的概览,使用了只读的分层次的接口函数,它们有利于文档的检索和输出。 - 对于文档的读取和编辑要使用不同方面的两组接口。
1)文档的光标主要基于QTextCursor类。
2)文档的框架主要基于QTextDocument类。 - 一个富文本文档的结构被分为了几种元素来表示,分别是框架(QTextFrame)、文本块(QTextBlock)、表格(QTextTable)和列表(QTextList)。 每种元素的格式又使用相应的format类来表示,它们分别是框架格式(QTextFrameFormat)、文本块格式(QTextBlockFormat)、表格格式(QTextTableFormat)和列表格式(QTextListFormat),这些格式一般在编辑文档时使用,所以它们常和QTextCursor类配合使用。
- 因为QTextEdit类就是一个富文本编辑器,所以在构建QTextEdit类的对象时就已经构建了一个QTextDocument类对象和一个QTextCursor类对象,只需调用它们进行相应的操作即可。
- 一个空的文档包含了一个根框架(Root frame),这个根框架又包含了一个空的文本块(Block)。框架将一个文档分为多个部分,在根框架里可以再添加文本块、子框架和表格等。


15.6.1.1 设置根框架
cpp
QTextDocument *document = ui->textEdit->document(); //获取文档对象
QTextFrame *rootFrame = document->rootFrame(); // 获取根框架
QTextFrameFormat format; // 创建框架格式
format.setBorderBrush(Qt::red); // 边界颜色
format.setBorder(3); // 边界宽度
rootFrame->setFrameFormat(format); // 框架使用格式
15.6.1.2 添加子框架
cpp
QTextFrameFormat frameFormat;
frameFormat.setBackground(Qt::lightGray); // 设置背景颜色
frameFormat.setMargin(10); // 设置边距
frameFormat.setPadding(5); // 设置填衬
frameFormat.setBorder(2);
//设置边框样式
frameFormat.setBorderStyle(QTextFrameFormat::BorderStyle_Dotted);
QTextCursor cursor = ui->textEdit->textCursor(); // 获取光标
cursor.insertFrame(frameFormat); // 在光标处插入框架
15.6.2 文本块
- 文本块QTextBlock类为文本文档QTextDocument提供了一个文本片段(QTextFragment)的容器。
- 一个文本块可以看做是一个段落,但是它不能使用回车换行,因为一个回车换行就表示创建一个新的文本块。QTextBlock提供了只读接口,它是前面提到的文档分层次的接口的一部分,如果QTextFrame看做是一层,那么其中的QTextBlock就是另一层。
- 文本块的格式由QTextBlockFormat类来处理,它主要涉及对齐方式,文本块四周的边白,缩进等内容。而文本块中的文本内容的格式,比如字体大小、加粗、下划线等内容,则由QTextCharFormat类来设置。
15.6.2.1 遍历框架
cpp
QTextDocument *document = ui->textEdit->document();
QTextFrame *frame = document->rootFrame();
QTextFrame::iterator it; // 建立QTextFrame类的迭代器
for (it = frame->begin(); !(it.atEnd()); ++it) {
QTextFrame *childFrame = it.currentFrame();// 获取当前框架的指针
QTextBlock childBlock = it.currentBlock(); // 获取当前文本块
if (childFrame)
qDebug() << "frame";
else if (childBlock.isValid())
qDebug() << "block:" << childBlock.text();
}

15.6.2.2 遍历子框架
cpp
QTextDocument *document = ui->textEdit->document();
QTextBlock block = document->firstBlock(); // 获取文档的第一个文本块
for (int i = 0; i < document->blockCount(); i++) {
qDebug() << tr("文本块%1,文本块首行行号为:%2,长度为:%3,内容为:")
.arg(i).arg(block.firstLineNumber()).arg(block.length())
<< block.text();
block = block.next(); // 获取下一个文本块
}

15.6.2.3 编辑文本块及其内容的格式
cpp
QTextCursor cursor = ui->textEdit->textCursor();
QTextBlockFormat blockFormat; // 文本块格式
blockFormat.setAlignment(Qt::AlignCenter); // 水平居中
cursor.insertBlock(blockFormat); // 使用文本块格式
QTextCharFormat charFormat; // 字符格式
charFormat.setBackground(Qt::lightGray); // 背景色
charFormat.setForeground(Qt::blue); // 字体颜色
// 使用宋体,12号,加粗,倾斜
charFormat.setFont(QFont(tr("宋体"), 12, QFont::Bold, true));
charFormat.setFontUnderline(true); // 使用下划线
cursor.setCharFormat(charFormat); // 使用字符格式
cursor.insertText(tr("测试字体")); // 插入文本

15.6.3 表格、列表与图片
- 插入表格
cpp
QTextCursor cursor = ui->textEdit->textCursor();
QTextTableFormat format; // 表格格式
format.setCellSpacing(2); // 表格外边白
format.setCellPadding(10); // 表格内边白
cursor.insertTable(2, 2, format); // 插入2行2列表格
- 插入列表
cpp
QTextListFormat format; // 列表格式
format.setStyle(QTextListFormat::ListDecimal); // 数字编号
ui->textEdit->textCursor().insertList(format);
- 插入图片
cpp
QTextImageFormat format; // 图片格式
format.setName("logo.png"); // 图片路径
ui->textEdit->textCursor().insertImage(format);

15.6.4 查找功能
- 查找文本
cpp
QDialog *dlg = new QDialog(this); // 创建对话框
lineEdit = new QLineEdit(dlg); // 创建行编辑器
QPushButton *btn = new QPushButton(dlg); // 创建按钮
btn->setText(tr("查找下一个"));
connect(btn,SIGNAL(clicked()),this,SLOT(findNext())); // 关联信号和槽
QVBoxLayout *layout = new QVBoxLayout; // 创建垂直布局管理器
layout->addWidget(lineEdit); // 添加部件
layout->addWidget(btn);
dlg->setLayout(layout); // 在对话框中使用布局管理器
dlg->show();
- 查找下一个
cpp
QString string = lineEdit->text();
// 使用查找函数查找指定字符串,查找方式为向后查找
bool isfind = ui->textEdit->find(string, QTextDocument::FindBackward);
if (isfind) { // 如果查找成功,输出字符串所在行和列的编号
qDebug() << tr("行号:%1 列号:%2")
.arg(ui->textEdit->textCursor().blockNumber())
.arg(ui->textEdit->textCursor().columnNumber());
}

15.6.5 语法高亮与HTML
15.6.5.1 语法高亮
- 在使用Qt Creator编辑代码时可以发现,输入关键字时会显示不同的颜色,这就是所谓的语法高亮。
- 在Qt的富文本处理中提供了QSyntaxHighlighter类来实现语法高亮。为了实现这个功能,需要创建QSyntaxHighlighter类的子类,然后重新实现highlightBlock()函数,使用时直接将QTextDocument类对象指针作为其父部件指针,这样就可以自动调用highlightBlock()函数了。
- 例如,自定义的类为MySyntaxHighlighter,像这样来使用:
cpp
highlighter = new MySyntaxHighlighter(ui->textEdit->document());
这里创建了MySyntaxHighlighter类的对象,并且使用编辑器的文档对象指针作为其参数,这样,每当编辑器中的文本改变时都会调用highlightBlock()函数来设置语法高亮。
cpp
QTextCharFormat myFormat; // 字符格式
myFormat.setFontWeight(QFont::Bold);
myFormat.setForeground(Qt::green);
QString pattern = "\\bchar\\b"; // 要匹配的字符,这里是"char"单词
QRegularExpression expression(pattern); // 创建正则表达式
QRegularExpressionMatchIterator i = expression.globalMatch(text);
while (i.hasNext()) { // 使用匹配迭代器来获取高亮字符的位置并设置格式
QRegularExpressionMatch match = i.next();
setFormat(match.capturedStart(), match.capturedLength(), myFormat);
}
这里主要使用了正则表达式来进行字符串的匹配,如果匹配成功,则使用QSyntaxHighlighter类的setFormat()函数来设置字符格式。
15.6.5.2 HTML
在富文本处理中还提供了对HTML子集的支持,可以在QLabel或者QTextEdit添加文本时使用HTML标签或者CSS属性,例如:
cpp
ui->textEdit->append(tr("<h1><font color=red>使用HTML</font></h1>"));
这里往编辑器中添加了文本,并且使用了HTML标签。

15.7 打印文档
Qt 5版本以后,Qt Print Support模块提供了对打印的支持。只需要使用一个QPrinter类和一个打印对话框QPrintDialog类就可以完成文档的打印操作。
15.7.1 打印文档
cpp
QPrinter printer; // 创建打印机对象
QPrintDialog dlg(&printer, this); // 创建打印对话框
if (dlg.exec() == QDialog::Accepted) { // 如果在对话框中按下了打印按钮
ui->textEdit->print(&printer); // 则执行打印操作
}
在这里先建立了QPrinter类对象,它代表了一个打印设备。然后创建了一个打印对话框。
15.7.2 打印预览
cpp
QPrinter printer;
QPrintPreviewDialog preview(&printer, this); // 创建打印预览对话框
// 当要生成预览页面时,发射paintRequested()信号
connect(&preview, &QPrintPreviewDialog::paintRequested, this, &MainWindow::printPreview);
preview.exec();
//对应的槽:
void MainWindow::printPreview(QPrinter *printer)
{
ui->textEdit->print(printer);
}
这里主要使用打印预览对话框来进行打印预览,这里要关联它的paintRequested()信号到槽上,在槽中调用编辑器的打印函数,并以传来的QPrinter类对象指针为参数。

15.7.3 生成PDF文档
cpp
QString fileName = QFileDialog::getSaveFileName(this, tr("导出PDF文件"),
QString(), "*.pdf");
if (!fileName.isEmpty()) {
if (QFileInfo(fileName).suffix().isEmpty())
fileName.append(".pdf"); // 如果文件后缀为空,则默认使用.pdf
QPrinter printer;
printer.setOutputFormat(QPrinter::PdfFormat); // 指定输出格式为pdf
printer.setOutputFileName(fileName);
ui->textEdit->print(&printer);
}
在生成PDF文档的槽中,使用文件对话框来获取要保存文件的路径,如果文件名没有指定后缀则为其添加".pdf"后缀。然后为QPrinter对象指定输出格式和文件路径,这样就可以将文档打印成PDF格式了。