Qt中使用QPdfWriter类结合QPainter类绘制并输出PDF文件
一.类的介绍
1.QPdfWriter介绍
Qt中提供了一个直接可以处理PDF的类,这就是QPdfWriter类。
(1)PDF文件生成
支持创建新的PDF文件或覆盖已有文件,通过构造函数直接绑定文件路径或QFile对象;
默认生成矢量图形PDF,支持高分辨率输出(可设置DPI);
(2)页面属性配置
页面方向:通过setPageOrientation(QPageLayout::Orientation)设置纵向(Portrait)或横向(Landscape);
页面尺寸:使用setPageSize(QPageSize::A4)定义纸张大小,支持ISO标准尺寸(如A4、A3);
页边距:通过setPageMargins()调整内容区域与页边的距离;
(3)内容绘制
与QPainter深度集成,支持所有标准绘图操作:
图形:线段、矩形、椭圆、多边形等;
文本:多字体样式、对齐方式、旋转文字;
图像:支持PNG、JPG、SVG等格式的嵌入;
(4)多页面管理
通过QPainter::begin()和QPainter::end()控制绘制流程;
使用QPrinter::newPage()或手动分页逻辑实现多页文档;
2.QPainter介绍
(1)QPainter类功能
QPainter是Qt框架中用于2D图形绘制的核心类,提供高度优化的绘图功能,支持在QWidget、QImage、QPixmap、QPrinter等设备上进行绘制。其主要特性包括:
- 支持矢量图形(直线/曲线/几何图形)和位图操作;
- 提供坐标变换、复合模式、抗锯齿等高级特性;
- 集成字体渲染、图像合成等专业级功能;
- 必须通过paintEvent()事件或在继承自QPaintDevice的类中使用;
(2)QPainter类接口
- 基础绘图操作

- 文本与图像处理

- 状态控制与高级特性

QPainter类还有很多接口函数,尤其是跟绘制有关的,很多重载的接口方便不同情况的使用,具体可以参考官网的介绍QPainter类。
二.开发生成PDF文件
下面开始用上文中的两个类来封装一个专门用来绘制PDF文件的类。
1.使用前要注意:
- 坐标系系统:PDF坐标系原点在页面左上角,Y轴向下延伸,X轴向右延伸;
- 单位换算:使用QPageLayout::Millimeter设置毫米单位,绘制时默认使用像素单位;
- 图像缩放:推荐使用QRect参数控制图片显示尺寸,避免直接缩放;
- 字体嵌入:中文字体需通过QFontDatabase加载系统字体;
- 多页处理:通过QPdfWriter的newPage()创建新页面;
2.绘制流程梳理
- 想要操作PDF文件,首先得有个文件,使用QFile的对象指向文件,然后创建QPdfWriter类的对象,并将QPdfWriter绑定在该文件上,然后用QPdfWriter对象设定PDF的一些参数,比如DPI,绘制页面大小等。
- 其次,想要绘制得打开文件,调用QFile对象打开绑定的pdf格式的文件;
- 再次,创建QPainter类对象,用该对象的各个规制接口来绘制各种图形文字等,如果你要设计绘制的接口很多的话,这里其实是最耗时的;
- 最后,正确的释放资源,关闭文件;
3.代码说明
现在实操
- QtCreator上创建一个简单的应用程序项目,先编译下,确保原始项目没问题;
- 在程序界面上添加一个按钮,命名“btCreatePdf”,连接好按钮对应的点击信号槽;
- 添加新的C++类,继承自QObject,类命名“PdfGenerator”,这就是我们准备开发的一个专门操作PDF的自定义类,也就是我们所有对PDF的操作都在这个类里边完成;
- “PdfGenerator”类的设计开发,包含QPdfWriter,QPainter,QFont,QImage,QPageSize, QFile等类;创建QPdfWriter类的对象,QPainter类的对象,QFile类的对象;调用这些对象的接口实现PDF的绘制。
- 最后,在主程序中包含上面自定义类,在界面按钮“btCreatePdf”中调用其实现PDF绘制。
不多说,直接上代码:
PdfGenerator 类的头文件:
// pdfgenerator.h
#include <QObject>
#include <QPdfWriter>
#include <QPainter>
#include <QFont>
#include <QImage>
#include <QPageSize>
#include <QFile>class PdfGenerator : public QObject {Q_OBJECT
public:explicit PdfGenerator(const QString &fileName, QPagedPaintDevice::PageSize size = QPagedPaintDevice::PageSize::A4);~PdfGenerator();// 基础设置 void setMargins(qreal left, qreal top, qreal right, qreal bottom);void setResolution(int dpi);void newPage();bool beginPage();bool endPage();// 绘制接口//绘制线段void drawLine(const QPointF &start, const QPointF &end, const QColor &color, qreal width);//绘制文字void drawText(const QRectF &rect, const QString &text, const QFont &font, const QColor &color, Qt::Alignment align);//绘制图片void drawImage(const QRectF &rect, const QString &imagePath, bool keepAspectRatio);//绘制矩形void drawRect(const QRectF &rect, const QColor &fillColor, const QColor &borderColor, qreal borderWidth);//绘制椭圆void drawEllipse(const QRectF &rect, const QColor &fillColor, const QColor &borderColor, qreal borderWidth);//想设计其他绘制接口继续往下加 private:QPdfWriter *m_writer = nullptr;QPainter *m_painter = nullptr;QRect m_pageRect;QFile m_pdfFile;
};
PdfGenerator 类的cpp文件
#include "PdfGenerator.h"
#include <QtDebug>
// pdfgenerator.cpp
PdfGenerator::PdfGenerator(const QString &fileName, QPagedPaintDevice::PageSize size)
{m_pdfFile.setFileName(fileName);m_writer = new QPdfWriter(&m_pdfFile);m_writer->setPageSize(size);m_writer->setResolution(300);m_writer->setPageMargins(QMarginsF(20, 20, 20, 20), QPageLayout::Millimeter);m_pageRect = m_writer->pageLayout().paintRectPixels(m_writer->resolution());// 计算可绘制区域 m_pageRect = QRect(0, 0, m_writer->width(), m_writer->height());if(!m_pdfFile.open(QIODevice::WriteOnly))return ;}PdfGenerator::~PdfGenerator()
{if (m_painter->isActive()){m_painter->end();}delete m_painter;delete m_writer;
}void PdfGenerator::setMargins(qreal left, qreal top, qreal right, qreal bottom)
{m_writer->setPageMargins(QMarginsF(left, top, right, bottom), QPageLayout::Millimeter);m_pageRect = m_writer->pageLayout().paintRectPixels(m_writer->resolution()); // 更新绘制区域[5]()
}void PdfGenerator::newPage()
{// 创建新页m_writer->newPage();
}bool PdfGenerator::beginPage(){bool bRet = false;if(nullptr == m_painter){m_painter = new QPainter(m_writer);}//启用抗锯齿m_painter->setRenderHint(QPainter::Antialiasing);if (nullptr != m_painter){m_painter->begin(m_writer);//m_painter->reset(new QPainter(m_writer.data()));bRet = m_painter->isActive();}qDebug() << "beginPage bRet is " << bRet;return bRet;
}bool PdfGenerator::endPage() {if (m_painter && m_painter->isActive()){m_painter->end();m_writer->deleteLater();m_pdfFile.close();return true;}m_pdfFile.close();return false;
}// 绘制线段
void PdfGenerator::drawLine(const QPointF &start, const QPointF &end, const QColor &color, qreal width)
{if (!m_painter->isActive())return;m_painter->save();m_painter->setPen(QPen(color, width));m_painter->drawLine(start, end);m_painter->restore();
}// 绘制文本(支持对齐)
void PdfGenerator::drawText(const QRectF &rect, const QString &text, const QFont &font, const QColor &color, Qt::Alignment align)
{if (!m_painter->isActive()) return;m_painter->save();m_painter->setFont(font);m_painter->setPen(color);m_painter->drawText(rect, static_cast<int>(align), text);m_painter->restore();
}// 绘制图片(自动缩放)
void PdfGenerator::drawImage(const QRectF &rect, const QString &imagePath, bool keepAspectRatio)
{if (!m_painter->isActive())return;QPixmap pixmap(imagePath);if (pixmap.isNull()) return;QRectF targetRect = rect;if (keepAspectRatio) {QSizeF scaled = pixmap.size().scaled(rect.size().toSize(), Qt::KeepAspectRatio);targetRect.setSize(scaled); }m_painter->drawPixmap(targetRect, pixmap, pixmap.rect());
}// 绘制矩形(支持填充)
void PdfGenerator::drawRect(const QRectF &rect, const QColor &fillColor, const QColor &borderColor, qreal borderWidth)
{if (!m_painter->isActive())return;m_painter->save();m_painter->setBrush(QBrush(fillColor));m_painter->setPen(QPen(borderColor, borderWidth));m_painter->drawRect(rect);m_painter->restore();
}// 绘制椭圆
void PdfGenerator::drawEllipse(const QRectF &rect, const QColor &fillColor, const QColor &borderColor, qreal borderWidth)
{if (!m_painter->isActive()) return;m_painter->save();m_painter->setBrush(QBrush(fillColor));m_painter->setPen(QPen(borderColor, borderWidth));m_painter->drawEllipse(rect);m_painter->restore();
}
主程序按钮调用PdfGenerator类绘制PDF
//创建Pdf
void MainWindow::on_btCreatePdf_clicked()
{qDebug() << "into on_btCreatePdf_clicked";PdfGenerator doc("E:/test/output.pdf");if (doc.beginPage()){qDebug() << "beginPage success";// 绘制灰色线段doc.drawLine(QPointF(20, 60), QPointF(150, 200), Qt::lightGray, 2.0);// 添加图片(保持比例),例子的资源里没有添加这张图片,所以下面PDF里没有绘制出来图片doc.drawImage(QRectF(100, 100, 100, 100), "logo.png", false);// 绘制蓝色文字QFont font("Arial", 12, QFont::Bold);doc.drawText(QRectF(70, 270, 270, 50), "Hello PDF!", font, Qt::blue, Qt::AlignVCenter | Qt::AlignHCenter);// 绘制绿色填充矩形doc.drawRect(QRectF(300, 150, 100, 40), Qt::green, Qt::black, 1.5);// 绘制黄色边框椭圆doc.drawEllipse(QRectF(250, 200, 100, 80), Qt::transparent, Qt::yellow, 2.0);doc.endPage();}}
执行后,展示结果:

以此自定义PdfGenerator类作为基础,后续可以根据QPainter类本身带有的各种图形绘制功能,封装你想做的绘制接口,实际项目应用中,就以你封装的接口进行各种布局绘制操作,来完成项目要求。
相关文章:
Qt中使用QPdfWriter类结合QPainter类绘制并输出PDF文件
一.类的介绍 1.QPdfWriter介绍 Qt中提供了一个直接可以处理PDF的类,这就是QPdfWriter类。 (1)PDF文件生成 支持创建新的PDF文件或覆盖已有文件,通过构造函数直接绑定文件路径或QFile对象; 默认生成矢量图形PDF&#…...
Android开发-深入解析Android中的AIDL及其应用场景
深入解析 Android 中的 AIDL 及其应用场景 1. 前言2. AIDL 的核心概念3. AIDL 的实现步骤3.1. 定义 AIDL 接口文件3.2. 实现服务端(Service)3.3. 客户端绑定与调用 4. AIDL 的典型应用场景4.1. 多进程应用4.2. 与系统服务交互4.3. 高性能 IPC4.4. 跨应用…...
RT-Thread+STM32L475VET6实现红外遥控实验
文章目录 前言一、板载资源介绍二、具体步骤1. 确定红外接收头引脚编号2. 下载infrared软件包3. 配置infrared软件包4. 打开STM32CubeMX进行相关配置4.1 使用外部高速时钟,并修改时钟树4.2 打开定时器16(定时器根据自己需求调整)4.3 打开串口4.4 生成工程 5. 打开HW…...
【机器学习】衡量线性回归算法最好的指标:R Squared
衡量线性回归算法最好的指标:R Squared 一、摘要二、回归算法评价指标与R Squared指标介绍三、R Squared的编程实践 一、摘要 本文主要介绍了线性回归算法中用于衡量模型优劣的重要指标——R Squared(R方)。R方用于比较模型预测结果与实际结…...
设计模式-Java
一、创建型模式 1. 单例模式 定义 确保一个类只有一个实例,并提供一个全局访问点。 实现方式 饿汉式(线程安全,但可能浪费资源) public class Singleton {// 静态变量,类加载时初始化private static final Singlet…...
代码讲解系列-CV(五)——语义分割基础
文章目录 一、图像分割标注1.1 Labelme标注1.2 SAM辅助1.3 json格式 二、数据解析2.1 Dataset2.2 train.py2.2.1 取参2.2.2 分割和数据集的读取 三、Unet网络搭建3.1 Unet3.2 Network 四、损失函数和指标4.1 DICE系数4.2 损失函数4.3 半精度训练 五、SAM六、作业 语义分割是图片…...
在mfc中使用自定义三维向量类和计算多个三维向量的平均值
先添加一个普通类, Vector3.h, // Vector3.h: interface for the Vector3 class. // //#if !defined(AFX_VECTOR3_H__53D34D26_95FF_4377_BD54_57F4271918A4__INCLUDED_) #define AFX_VECTOR3_H__53D34D26_95FF_4377_BD54_57F4271918A4__INCLUDED_#if _MSC_VER > 1000 #p…...
RDMA ibverbs_API功能说明
设备管理 获取当前活动网卡 返回当前rdma设备列表 struct ibv_device **ibv_get_device_list(int *num_devices);//使用 struct ibv_device **dev_list ibv_get_device_list(NULL);获取网卡名 返回网卡名字字符串:如"mlx5_0",一般通过网卡…...
【C++语言】string 类
一、为什么要学习 string 类 C语言中,字符串是以 “\0” 结尾的一些字符的集合,为了操作方便,C标准库中提供了一些 str 系列的库函数,但是这些库函数与字符串是分离开的,不太符合 OOP 的思想,而且底层空间需…...
快速上手gdb/cgdb
Linux调试器-gdb使用 1.背景2.调试原理、技巧命令2.1指令2.2 本质2.3 技巧 1.背景 程序的发布方式有两种,debug模式和release模式 Linux gcc/g出来的二进制程序,默认是release模式 要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g…...
《养生》(二)
一、基础生活调整 1.作息规律 固定每天7-8小时睡眠,尽量22:30前入睡,晨起后拉开窗帘晒太阳5分钟,调节生物钟 2.饮食优化 三餐定时,每餐细嚼慢咽20次以上,优先吃蔬菜和蛋白质(如鸡蛋、豆腐&#x…...
JAVA:集成 Drools 业务规则引擎的技术指南
1、简述 Drools 是一个强大的业务规则引擎,适用于需要动态决策或规则管理的场景。它允许开发人员将业务逻辑与应用代码分离,使得业务人员可以通过规则文件维护和更新规则,而无需修改应用代码。本文将介绍 Drools 的基本概念、配置方式&#…...
GeoHD - 一种用于智慧城市热点探测的Python工具箱
GeoHD - 一种用于智慧城市热点探测的Python工具箱 详细原理请参考:Yan, Y., Quan, W., Wang, H., 2024. A data‐driven adaptive geospatial hotspot detection approach in smart cities. Trans. GIS tgis.13137. 代码下载:下载 1. 简介 在城市数据…...
记一次Ngnix配置
记一次Ngnix配置 配置Ngnix配置防火墙 假设一个服务器中有一个公网IP、一个内网IP,另外已经部署好后台服务的接口地址为http://内网ip:8088。 配置Ngnix 找到Ngnix的配置文件,通过在Ngnix的安装路径下的 \conf\nginx.conf 文件。 worker_processes 1;…...
2024年国赛高教杯数学建模C题农作物的种植策略解题全过程文档及程序
2024年国赛高教杯数学建模 C题 农作物的种植策略 原题再现 根据乡村的实际情况,充分利用有限的耕地资源,因地制宜,发展有机种植产业,对乡村经济的可持续发展具有重要的现实意义。选择适宜的农作物,优化种植策略&…...
java基础语知识(8)
类之间的关系 在类之间,最常见的关系有: 依赖(“uses-a”);聚合(“has-a”);继承(“is-a”)。 依赖:一种使用关系,即一个类的实现需要另一个类的协助&#x…...
室内定位精度方案对比
室内定位精度方案对比:成本、开发难度与精度的权衡 索引 引言 Wi-Fi 定位方案 定位原理 成本分析 开发难度 定位精度 蓝牙定位方案 定位原理 成本分析 开发难度 定位精度 超宽带(UWB)定位方案 定位原理 成本分析 开发难度 定…...
Pytorch深度学习教程_5_编写第一个神经网络
欢迎来到《pytorch深度学习教程》系列的第五篇!在前面的四篇中,我们已经介绍了Python、numpy及pytorch的基本使用,并在上一个教程中介绍了梯度。今天,我们将探索神经网络,对于神经网络进行概述并进行简单的实践学习 欢…...
ImportError: cannot import name ‘FixtureDef‘ from ‘pytest‘
错误信息表明 pytest 在尝试导入 FixtureDef 时出现了问题。通常是由于 pytest 版本不兼容 或 插件版本冲突 引起的。以下是详细的排查步骤和解决方案: 1. 检查 pytest 版本 首先,确认当前安装的 pytest 版本。某些插件可能需要特定版本的 pytest 才能…...
改BUG:Mock测试的时候,when失效
问题再现: 这里我写了一测试用户注册接口的测试类,并通过when模拟下层的服务,但实际上when并没有奏效,还是走了真实的service层的逻辑。 package cn.ac.evo.review.test;import cn.ac.evo.review.user.UserMainApplication; imp…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
