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

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类本身带有的各种图形绘制功能,封装你想做的绘制接口,实际项目应用中,就以你封装的接口进行各种布局绘制操作,来完成项目要求。


http://www.kler.cn/a/556073.html

相关文章:

  • 15增减字符串匹配(贪心)思路解析+源码
  • WPS接入deepseek-OfficeAI助手插件下载
  • 武汉火影数字|VR沉浸式空间制作 VR大空间打造
  • Spring面试题2
  • uniapp引入ucharts组件不显示
  • Flask flash() 消息示例
  • ChatGPT付费创作系统V3.1.3独立版 WEB端+H5端+小程序端 (DeepSeek高级通道+推理输出格式)安装教程
  • 在windows下安装windows+Ubuntu16.04双系统(上)
  • Visual Studio 开发 C# 项目 VS. QT 开发 C++ 项目:全面对比与选择指南
  • 4.4/Q1,FAERS数据库最新文章解读!
  • 虚拟机的创建及配置
  • 【Python项目】基于Python的Web漏洞挖掘系统
  • 深入理解 C++17 的缓存行接口
  • 用Python实现的双向链表类,包含了头插、尾插、归并排序等功能
  • STM32-温湿度上传OneNET项目
  • 这个TensorFlow是一个开源的机器学习框架,怎么用
  • 【蓝桥杯集训·每日一题2025】 AcWing 6135. 奶牛体检 python
  • Scala的宝藏库:探索常用的第三方库及其应用
  • OpenCV机器学习(8)随机森林(Random Forests)算法cv::ml::RTrees类
  • 【Java学习】多态