提示: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()步骤,具有高拓展性的特点。
缺点:
- 当遇到Windows设置系统缩放时,QWidget会发生相应的变化,所以为了保证各种缩放下的自适应,需要对文本设置点大小、对.ui文件布局做出调整等的工作;
- 相较于直接使用QPainter方式进行绘制的方案,因为需要创建一个甚至多个QWidget资源,所以会带来些许的资源负荷;
- MacOS系统下,根据Qt官方文档,render函数会采用截图的方式,所以矢量方案会失效(但作者未对其进行验证);
- QCustomPlot依旧会采用像素级图像的方式进行绘制,该缺陷会在3.中进行解决。
- …
3. QCustomPlot适配
由于作者本人在PDF报告中使用了该组件库来绘制图形,故单独拿一小章内容来解决QCustomPlot的适配问题,有同样需求的读者可以接续阅读。
当QWidget中嵌套了QCustomPlot组件时,使用矢量级绘制方案还是会导致像素级QCustomPlot的绘制(源码中应该会找到相应的原因,感兴趣的可以阅读,此处不再展开,仅描述解决方案)。作者查阅了QCustomPlot的官方文档,官方很详细地提供了void QCustomPlot::toPainter ( QCPPainter * painter, int width = 0, int height = 0 )
函数和解决方案。
在此,我们需要借助QLabel来承载QPicture,然后嵌入到QWidget来实现,代码如下:
QLabel label;
QCustomPlot qcp;
QPicture picture;
{
QCPPainter painter(&picture);
qcp.toPainter(&painter);
}
label.setPicture(picture);
总结
文章对比了市面上常用的Qt设计和打印PDF文档的方案,并给出了一种矢量级绘制的方案,同时就QCustomPlot存在的问题进行了适配。
感谢您的仔细阅读,如果发现文章中的不足之处,您可以给予指正和建议,这是对我莫大的提升,再次感谢!