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.pswp.cn/diannao/70376.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/70376.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/70376.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Golang GORM系列:GORM無縫集成web框架

高效的數據管理是每個成功的web應用程序的支柱。GORM是通用的Go對象關系映射庫&#xff0c;它與流行的Go web框架搭配得非常好&#xff0c;提供了無縫集成&#xff0c;簡化了數據交互。本指南將帶你探索GORM和web框架&#xff08;如Gin&#xff0c; Echo和Beego&#xff09;之間…

SAM C++ TensorRT(實時圖像分割)

SPEED SAM C TENSORRT &#x1f310; 1、概述 用于SAM&#xff08;segment anything model分割一切模型&#xff09;的TensorRT和CUDA優化的高表現C實現&#xff0c;特別適用于實時圖像分割任務。 &#x1f4e2; 更新 模型轉換&#xff1a;從ONNX模型構建TensorRT引擎以加速…

【LLAMA】羊駝從LLAMA1到LLAMA3梳理

every blog every motto: Although the world is full of suffering&#xff0c; it is full also of the overcoming of it 0. 前言 LLAMA 1到3梳理 1. LLAMA 1 論文&#xff1a; LLaMA: Open and Efficient Foundation Language Models 時間&#xff1a; 2023.02 1.1 前言…

什么是網絡安全?網絡安全防范技術包括哪些?

伴隨著互聯網的發展&#xff0c;它已經成為我們生活中不可或缺的存在&#xff0c;無論是個人還是企業&#xff0c;都離不開互聯網。正因為互聯網得到了重視&#xff0c;網絡安全問題也隨之加劇&#xff0c;給我們的信息安全造成嚴重威脅&#xff0c;而想要有效規避這些風險&…

【從0做項目】Java搜索引擎(7) web模塊

阿華代碼&#xff0c;不是逆風&#xff0c;就是我瘋 你們的點贊收藏是我前進最大的動力&#xff01;&#xff01; 希望本文內容能夠幫助到你&#xff01;&#xff01; 目錄 文章導讀 零&#xff1a;項目結果展示 一&#xff1a;后端web模塊 1&#xff1a;思路 2&#xff1a…

Visual Studio Code 集成 Baidu Comate

文章目錄 安裝Baidu Comate插件 安裝Baidu Comate插件 從左主側欄中 點擊 【擴展】這個圖標&#xff0c;然后在上方輸入欄中輸入 baidu comate —>選中列出的Bai Comate —>點擊 【安裝】按鈕&#xff0c;等待安裝完畢…

WeMos D1+PIR+Android 的小場景制作

最近在做一個有趣的小場景功能&#xff0c;其實已經有成熟產品&#xff0c;但是考慮到沒法實現場景擴展&#xff0c;所以自己開始動手做。 場景描述&#xff1a;玄關人體感應&#xff0c;有人進門&#xff0c;致歡迎詞&#xff0c;有人離開&#xff0c;致歡送詞。 硬件設備&a…

Android ListPreference使用

Android ListPreference使用 參考 添加鏈接描述 導入 androidx.preference.ListPreferenceListPreference是Android中的一個Preference子類,用于顯示一個可選擇的列表,并且可以保存用戶所選擇的值。它繼承自DialogPreference,可以在用戶點擊時彈出一個對話框,顯示可選擇的…

Spring Security實現記住我功能的實戰指南

在現代Web應用中&#xff0c;"記住我"功能是提升用戶體驗的重要特性之一。用戶無需在每次訪問時重新登錄&#xff0c;這不僅方便&#xff0c;還能增強用戶對應用的粘性。今天&#xff0c;我們將通過一個具體的實例&#xff0c;詳細探討如何在Spring Security中實現&q…

用命令模式設計一個JSBridge用于JavaScript與Android交互通信

用命令模式設計一個JSBridge用于JavaScript與Android交互通信 在開發APP的過程中&#xff0c;通常會遇到Android需要與H5頁面互相傳遞數據的情況&#xff0c;而Android與H5交互的容器就是WebView。 因此要想設計一個高可用的 J S B r i d g e JSBridge JSBridge&#xff0c;不…

ModuleNotFoundError: No module named ‘timm.optim.novogr兩種解決方法

運行報錯 from timm.optim.novograd import NovoGradModuleNotFoundError: No module named ‘timm.optim.novograd’。 問題原因 timm版本過高&#xff0c;novograd函數已被拋棄。 解決辦法 方法1&#xff1a;安裝更低版本的timm pip install timm0.4.12方法2&#xff1a…

DeepSeek 本地部署指南:從零開始搭建 AI 搜索工具

1. 引言 背景介紹 DeepSeek 是一款基于 AI 的搜索工具&#xff0c;能夠高效處理海量數據&#xff0c;提供精準的搜索結果。它結合了 Ollama 的模型管理能力&#xff0c;使得部署更加便捷。 為什么選擇本地部署 本地部署可以確保數據隱私&#xff0c;避免云端傳輸的風險&…

昇騰DeepSeek模型部署優秀實踐及FAQ

2024年12月26日&#xff0c;DeepSeek-V3橫空出世&#xff0c;以其卓越性能備受矚目。該模型發布即支持昇騰&#xff0c;用戶可在昇騰硬件和MindIE推理引擎上實現高效推理&#xff0c;但在實際操作中&#xff0c;部署流程與常見問題困擾著不少開發者。本文將為你詳細闡述昇騰 De…

vscode復制到下一行

linux中默認快捷鍵是ctrl shift alt down/up 但是在vscode中無法使用&#xff0c;應該是被其他的東西綁定了&#xff0c;經測試&#xff0c;可以使用windows下的快捷鍵shift alt down/up { “key”: “shiftaltdown”, “command”: “editor.action.copyLinesDownAction”…

網絡爬蟲學習:借助DeepSeek完善爬蟲軟件,實現模擬鼠標右鍵點擊,將鏈接另存為本地文件

一、前言 最近幾個月里&#xff0c;我一直在學習網絡爬蟲方面的知識&#xff0c;每有收獲都會將所得整理成文發布&#xff0c;不知不覺已經發了7篇日志了&#xff1a; 網絡爬蟲學習&#xff1a;從百度搜索結果抓取標題、鏈接、內容&#xff0c;并保存到xlsx文件中 網絡爬蟲學…

Arduino 第十六章:pir紅外人體傳感器練習

Arduino 第十六章&#xff1a;PIR 傳感器練習 一、引言 在 Arduino 的眾多有趣項目中&#xff0c;傳感器的應用是非常重要的一部分。今天我們要學習的主角是 PIR&#xff08;被動紅外&#xff09;傳感器。PIR 傳感器能夠檢測人體發出的紅外線&#xff0c;常用于安防系統、自動…

CV -- YOLOv8 圖像分割(GPU環境)

目錄 參考視頻&#xff1a; 標注 JSON轉為TXT 訓練 驗證 參考視頻&#xff1a; 使用 Yolov8 自定義數據集進行圖像分割_嗶哩嗶哩_bilibili 標注 數據集&#xff1a; 我使用的是一些蘋果數據集&#xff0c;可以在我的csdn資源中下載&#xff1a; https://download.csdn.net/do…

深入理解 lua_KFunction 和 lua_CFunction

在 Lua C API 中,lua_KFunction 和 lua_CFunction 是兩個核心概念,尤其在處理協程和 C 函數擴展時扮演著至關重要的角色。lua_CFunction 作為一種 C 函數類型,允許開發者將 C 函數注冊到 Lua 環境中,使得這些 C 函數可以在 Lua 腳本中被調用,進而實現 Lua 的功能擴展。而 …

基于微信小程序的電影院訂票選座系統的設計與實現,SSM+Vue+畢業論文+開題報告+任務書+指導搭建視頻

本系統包含用戶、管理員兩個角色。 用戶角色&#xff1a;注冊登錄、查看首頁電影信息推薦、查看電影詳情并進行收藏預定、查看電影資訊、在線客服、管理個人訂單等。 管理員角色&#xff1a;登錄后臺、管理電影類型、管理放映廳信息、管理電影信息、管理用戶信息、管理訂單等。…

【Linux網絡編程】應用層協議HTTP(請求方法,狀態碼,重定向,cookie,session)

&#x1f381;個人主頁&#xff1a;我們的五年 &#x1f50d;系列專欄&#xff1a;Linux網絡編程 &#x1f337;追光的人&#xff0c;終會萬丈光芒 &#x1f389;歡迎大家點贊&#x1f44d;評論&#x1f4dd;收藏?文章 ? Linux網絡編程筆記&#xff1a; https://blog.cs…