【Qt】PDF报告设计、预览和打印

提示:Qt、C++、QPrinter、QWidget、QCustomPlot


前言

提示:Qt、C++、QWidget、QPrinter

本文介绍如何使用QWidget设计,QPrinter预览和打印PDF报告。此方案的优点主要是强拓展性,不需要第三方库;缺点是相对的资源消耗和Windows缩放影响。作者也对比了常见的Qt报告设计和生成方案,将在下文中进行阐述。


提示:以下是本篇文章正文内容,下面案例可供参考

一、常见技术方案

1. Word

创建Word文档模板,并于相应位置插入标签。使用QAxObject来访问Word文档,并替换相应标签的内容,最后转换为PDF。
缺点:借助Windows OS COM组件接口实现,所以用户需要安装MS Office或WPS。

1. 第三方库

使用QtRPT,LimeReport等第三方库。作者尝试了一下,主要用于报表类型例如表格的绘制。
缺点:需要借助和导入第三方库(有些是商业版权),拓展性差,设计困难(例如:页眉页脚)。

2. QTextDocument(HTML、MarkDown等富文本语言)

Qt笔记(四十九)之QTextDocument方式导出PDF
使用QTextDocument写入HTML、MarkDown等富文本语言,再使用QPrinter来预览和打印PDF,方案可查看上述超链接。
缺点:拓展性差,设计困难(例如:页眉页脚、表格),由于Qt富文本支持的版本较低导致部分富文本效果无法实现。

3. QPainter

使用Qt自带的QPainter绘制工具,绑定QPrinter或QPdfWriter后直接进行绘制。
缺点:拓展性差,工作量大。

二、QPainter + QWidget(报告设计)

借助Qt Designer工具,可以方便地为.ui文件进行报告的设计,QWidget设置该.ui文件后渲染到QPainter上。

1. 像素级绘制方案

下面先介绍存在瑕疵的方案,直接渲染到绑定了QPrinter的QPainter上:

QWidget widget;

/*
* Design the widget
* ...
*/

QPrinter printer;
{
QPainter painter(&printer);

painter.setRenderHint(QPainter::Antialiasing, true);
widget.render(&painter);
}

此方案最终导出的PDF文件以像素级图片形式渲染,所以PDF文件在放大后会异常模糊。这大概率是void QWidget::render(QPainter *painter, const QPoint &targetOffset = QPoint(), const QRegion &sourceRegion = QRegion(), QWidget::RenderFlags renderFlags = RenderFlags(DrawWindowBackground | DrawChildren))函数的实现导致的,感兴趣的可以详细阅读一下QWidget的源码。

也存在另一个方案与之类似,将QWidget通过grab()函数截图得到QPixmap,再调用QPainter的drawPixmap()函数进行绘制,同样也会得到异常模糊的PDF文档,故在此不再赘述。

2. 矢量级绘制方案

不同于上述的像素级绘制方案,该方案保证文字、线条等PDF中的元素均保持矢量。借助QWidget提供的另一个渲染函数:void QWidget::render(QPaintDevice *target, const QPoint &targetOffset = QPoint(), const QRegion &sourceRegion = QRegion(), QWidget::RenderFlags renderFlags = RenderFlags(DrawWindowBackground | DrawChildren))。该方案仅需借助QPicture来辅助,因为QPicture会记录QPainter所有绘制的步骤。

QWidget widget;
/*
* Design the widget
* ...
*/

QPicture picture;
widget.render(&picture);

QPrinter printer;
{
	QPainter painter(&printer);
	
	painter->drawPicture(0, 0, picture);
}

该方案充分利用了QWidget设置.ui文件就能完成报告设计工作的优点,同样也使用QPicture来记录QWidget(包括其子QWidget)的paintEvent()步骤,具有高拓展性的特点。
缺点:

  1. 当遇到Windows设置系统缩放时,QWidget会发生相应的变化,所以为了保证各种缩放下的自适应,需要对文本设置点大小、对.ui文件布局做出调整等的工作;
  2. 相较于直接使用QPainter方式进行绘制的方案,因为需要创建一个甚至多个QWidget资源,所以会带来些许的资源负荷;
  3. MacOS系统下,根据Qt官方文档,render函数会采用截图的方式,所以矢量方案会失效(但作者未对其进行验证);
  4. QCustomPlot依旧会采用像素级图像的方式进行绘制,该缺陷会在3.中进行解决。

3. QCustomPlot适配

由于作者本人在PDF报告中使用了该组件库来绘制图形,故单独拿一小章内容来解决QCustomPlot的适配问题,有同样需求的读者可以接续阅读。

当QWidget中嵌套了QCustomPlot组件时,使用矢量级绘制方案还是会导致像素级QCustomPlot的绘制(源码中应该会找到相应的原因,感兴趣的可以阅读,此处不再展开,仅描述解决方案)。作者查阅了QCustomPlot的官方文档,官方很详细地提供了void QCustomPlot::toPainter ( QCPPainter * painter, int width = 0, int height = 0 )函数和解决方案。
QCustomPlot::toPainter
在此,我们需要借助QLabel来承载QPicture,然后嵌入到QWidget来实现,代码如下:

QLabel label;
QCustomPlot qcp;
QPicture picture;
{
	QCPPainter painter(&picture);

	qcp.toPainter(&painter);
}
label.setPicture(picture);

总结

文章对比了市面上常用的Qt设计和打印PDF文档的方案,并给出了一种矢量级绘制的方案,同时就QCustomPlot存在的问题进行了适配。

感谢您的仔细阅读,如果发现文章中的不足之处,您可以给予指正和建议,这是对我莫大的提升,再次感谢!

  • 8
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值