当前位置: 首页 > news >正文

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类接口
  1. 基础绘图操作
    在这里插入图片描述
  2. 文本与图像处理
    在这里插入图片描述
  3. 状态控制与高级特性
    在这里插入图片描述
    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的类&#xff0c;这就是QPdfWriter类。 &#xff08;1&#xff09;PDF文件生成 支持创建新的PDF文件或覆盖已有文件&#xff0c;通过构造函数直接绑定文件路径或QFile对象&#xff1b; 默认生成矢量图形PDF&#…...

Android开发-深入解析Android中的AIDL及其应用场景

深入解析 Android 中的 AIDL 及其应用场景 1. 前言2. AIDL 的核心概念3. AIDL 的实现步骤3.1. 定义 AIDL 接口文件3.2. 实现服务端&#xff08;Service&#xff09;3.3. 客户端绑定与调用 4. AIDL 的典型应用场景4.1. 多进程应用4.2. 与系统服务交互4.3. 高性能 IPC4.4. 跨应用…...

RT-Thread+STM32L475VET6实现红外遥控实验

文章目录 前言一、板载资源介绍二、具体步骤1. 确定红外接收头引脚编号2. 下载infrared软件包3. 配置infrared软件包4. 打开STM32CubeMX进行相关配置4.1 使用外部高速时钟&#xff0c;并修改时钟树4.2 打开定时器16(定时器根据自己需求调整)4.3 打开串口4.4 生成工程 5. 打开HW…...

【机器学习】衡量线性回归算法最好的指标:R Squared

衡量线性回归算法最好的指标&#xff1a;R Squared 一、摘要二、回归算法评价指标与R Squared指标介绍三、R Squared的编程实践 一、摘要 本文主要介绍了线性回归算法中用于衡量模型优劣的重要指标——R Squared&#xff08;R方&#xff09;。R方用于比较模型预测结果与实际结…...

设计模式-Java

一、创建型模式 1. 单例模式 定义 确保一个类只有一个实例&#xff0c;并提供一个全局访问点。 实现方式 饿汉式&#xff08;线程安全&#xff0c;但可能浪费资源&#xff09; public class Singleton {// 静态变量&#xff0c;类加载时初始化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);获取网卡名 返回网卡名字字符串&#xff1a;如"mlx5_0"&#xff0c;一般通过网卡…...

【C++语言】string 类

一、为什么要学习 string 类 C语言中&#xff0c;字符串是以 “\0” 结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些 str 系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合 OOP 的思想&#xff0c;而且底层空间需…...

快速上手gdb/cgdb

Linux调试器-gdb使用 1.背景2.调试原理、技巧命令2.1指令2.2 本质2.3 技巧 1.背景 程序的发布方式有两种&#xff0c;debug模式和release模式 Linux gcc/g出来的二进制程序&#xff0c;默认是release模式 要使用gdb调试&#xff0c;必须在源代码生成二进制程序的时候, 加上 -g…...

《养生》(二)

一、基础生活调整 1‌.作息规律‌ 固定每天7-8小时睡眠&#xff0c;尽量22:30前入睡&#xff0c;晨起后拉开窗帘晒太阳5分钟&#xff0c;调节生物钟‌ ‌2.饮食优化‌ 三餐定时&#xff0c;每餐细嚼慢咽20次以上&#xff0c;优先吃蔬菜和蛋白质&#xff08;如鸡蛋、豆腐&#x…...

JAVA:集成 Drools 业务规则引擎的技术指南

1、简述 Drools 是一个强大的业务规则引擎&#xff0c;适用于需要动态决策或规则管理的场景。它允许开发人员将业务逻辑与应用代码分离&#xff0c;使得业务人员可以通过规则文件维护和更新规则&#xff0c;而无需修改应用代码。本文将介绍 Drools 的基本概念、配置方式&#…...

GeoHD - 一种用于智慧城市热点探测的Python工具箱

GeoHD - 一种用于智慧城市热点探测的Python工具箱 详细原理请参考&#xff1a;Yan, Y., Quan, W., Wang, H., 2024. A data‐driven adaptive geospatial hotspot detection approach in smart cities. Trans. GIS tgis.13137. 代码下载&#xff1a;下载 1. 简介 在城市数据…...

记一次Ngnix配置

记一次Ngnix配置 配置Ngnix配置防火墙 假设一个服务器中有一个公网IP、一个内网IP&#xff0c;另外已经部署好后台服务的接口地址为http://内网ip:8088。 配置Ngnix 找到Ngnix的配置文件&#xff0c;通过在Ngnix的安装路径下的 \conf\nginx.conf 文件。 worker_processes 1;…...

2024年国赛高教杯数学建模C题农作物的种植策略解题全过程文档及程序

2024年国赛高教杯数学建模 C题 农作物的种植策略 原题再现 根据乡村的实际情况&#xff0c;充分利用有限的耕地资源&#xff0c;因地制宜&#xff0c;发展有机种植产业&#xff0c;对乡村经济的可持续发展具有重要的现实意义。选择适宜的农作物&#xff0c;优化种植策略&…...

java基础语知识(8)

类之间的关系 在类之间&#xff0c;最常见的关系有&#xff1a; 依赖&#xff08;“uses-a”&#xff09;;聚合&#xff08;“has-a”&#xff09;;继承&#xff08;“is-a”&#xff09;。 依赖&#xff1a;一种使用关系&#xff0c;即一个类的实现需要另一个类的协助&#x…...

室内定位精度方案对比

室内定位精度方案对比&#xff1a;成本、开发难度与精度的权衡 索引 引言 Wi-Fi 定位方案 定位原理 成本分析 开发难度 定位精度 蓝牙定位方案 定位原理 成本分析 开发难度 定位精度 超宽带&#xff08;UWB&#xff09;定位方案 定位原理 成本分析 开发难度 定…...

Pytorch深度学习教程_5_编写第一个神经网络

欢迎来到《pytorch深度学习教程》系列的第五篇&#xff01;在前面的四篇中&#xff0c;我们已经介绍了Python、numpy及pytorch的基本使用&#xff0c;并在上一个教程中介绍了梯度。今天&#xff0c;我们将探索神经网络&#xff0c;对于神经网络进行概述并进行简单的实践学习 欢…...

ImportError: cannot import name ‘FixtureDef‘ from ‘pytest‘

错误信息表明 pytest 在尝试导入 FixtureDef 时出现了问题。通常是由于 pytest 版本不兼容 或 插件版本冲突 引起的。以下是详细的排查步骤和解决方案&#xff1a; 1. 检查 pytest 版本 首先&#xff0c;确认当前安装的 pytest 版本。某些插件可能需要特定版本的 pytest 才能…...

改BUG:Mock测试的时候,when失效

问题再现&#xff1a; 这里我写了一测试用户注册接口的测试类&#xff0c;并通过when模拟下层的服务&#xff0c;但实际上when并没有奏效&#xff0c;还是走了真实的service层的逻辑。 package cn.ac.evo.review.test;import cn.ac.evo.review.user.UserMainApplication; imp…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

【堆垛策略】设计方法

堆垛策略的设计是积木堆叠系统的核心&#xff0c;直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法&#xff0c;涵盖基础规则、优化算法和容错机制&#xff1a; 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则&#xff1a; 大尺寸/重量积木在下&#xf…...

rm视觉学习1-自瞄部分

首先先感谢中南大学的开源&#xff0c;提供了很全面的思路&#xff0c;减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接&#xff1a;https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架&#xff1a; 代码框架结构&#xff1a;readme有…...

动态规划-1035.不相交的线-力扣(LeetCode)

一、题目解析 光看题目要求和例图&#xff0c;感觉这题好麻烦&#xff0c;直线不能相交啊&#xff0c;每个数字只属于一条连线啊等等&#xff0c;但我们结合题目所给的信息和例图的内容&#xff0c;这不就是最长公共子序列吗&#xff1f;&#xff0c;我们把最长公共子序列连线起…...