admin管理员组

文章数量:1633094

近期需要使用PDF文件来生成数据报告。网络上有一些PDF的开源库,使用这些库往往需要编译安装,并且要花很多时间去研究原生接口。作为一个巧妙的(浮躁的)攻城狮,又正好在使用QT框架编写程序,灵光一闪,何不借助于QT这条大腿去实现PDF文件的创建呢,一试QT还真能很好的支持该需求。

本人所使用的:
QT版本:5.1x
语言: C++

首先在.pro 添加 模块
QT += printsupport

第一步:定义一个打印机

//几个相关头文件,一股脑加进来,实际上部分并没有使用,比如QPrintDialog QFontDialog
#include <QtPrintSupport/QPrintDialog>
#include <QtPrintSupport/QPrinter>
#include <QPainter>
#include <QFont>
#include <QFontDialog>
#include <QColor>

//定义打印机
    QPrinter text_printer;
    text_printer.setOutputFormat(QPrinter::PdfFormat);//设置PDF格式
    text_printer.setPageSize(QPrinter::A4);//设置纸张大小为A。
    text_printer.setOutputFileName("/home/xiaoming/test.pdf");

第二步:定义一个画家

//定义画家
    QPainter painter;  
    painter.setRenderHint(QPainter::Antialiasing);// 抗锯齿
    //painter.setFont(QFont("Ubuntu-BI", 40));
    QFont font;
    font.setPointSize(40);
    font.setFamily(QString("Ubuntu Regular"));
    font.setLetterSpacing(QFont::AbsoluteSpacing,0);
    painter.setFont(font);
    //获取这种字体情况下,文本的长度和高度
//    QFontMetricsF fontMetrics(font);
//    qreal wid = fontMetrics.width(scale_val_str);
//    qreal height = fontMetrics.height();

    QPen    ori_pen;
    ori_pen.setWidth(2);
    ori_pen.setColor(Qt::black);
    painter.setPen(ori_pen);

第三步:将画家的创作过程映射(呈现)在打印机的输出上

 //将画家的动作绑定到打印机上
    painter.begin(&text_printer);

Note: 设置drawText时的字体大小

本人实测时,发现以下方式设置字体大小时,打印出来的PDF文件字体大小并未生效。

QPen ori_pen;
== ori_pen.setWidth(xxx);==
== painter.setPen(ori_pen)。 // painter.setPen方式对DrawLine是有效的。==

== 于是,本人得知了 painter的drawText字体大小需要使用setFont方法。代码如下:==
QFont font = painter.font();
float fsize = font.pointSize();
font.setPointSizeF(font.pointSizeF()*2.0);//字体大小是之前的2倍
painter.setFont(font);
==不过,你以为这样就完事了? 这一段代码必须放在第三步(painter.begin(&text_printer);)之后才能生效。倘若将这段代码与第三步代码调换位置,那么设置字体大小居然死活不生效。 这也是我反复试了很多次发现的,属于一个坑吧! 我使用的是Ubuntu环境,不知道Win环境会不会这样子。也不知这一点与操作系统是否有关系。
但是有意思的是, painter.setPen放在第三步之前或者之后都能生效。 这算是一个小坑吧! ==

第四步:我左边画个龙,右边画个彩虹

int     lineHeight = 24;//每一行的高度
    QRect   rect = painter.viewport();//纸张的大小
    int     paperStartX = rect.x();   //纸张坐标系的起始X (左上角为原点)
    int     paperStartY = rect.y();   //纸张坐标系的起始Y (左上角为原点)
    int     paperWidth = rect.width();//纸张宽度

    //画左上角图标
    QPixmap pixmap(":/img/Resource/dragon.png");
    painter.drawPixmap(QRect(paperStartX + 0*pixmap.width(),paperStartY + 0* lineHeight,pixmap.width()*0.9,pixmap.height()*0.9), pixmap);
    //画右上角图标
    QPixmap pixmap_2(":/img/Resource/rainbow.png");
    painter.drawPixmap(QRect(paperStartX + paperWidth - 0.5*pixmap_2.width(),paperStartY + 0* lineHeight,pixmap_2.width()*0.5,pixmap_2.height()*0.5), pixmap_2);

drawPixmap参数说明:

inline void QPainter::drawPixmap(const QRect &r, const QPixmap &pm)
//r:画图的区域(将龙画在哪里);
//pm:要绘制的图像(龙)。
QRect(paperStartX + paperWidth - 0.5*pixmap_2.width(), //矩形左上角x坐标。0.5表示显示区域为原图的一半大
			paperStartY + 0* lineHeight,//矩形右上角Y坐标。0.5表示显示区域为原图的一半大
			pixmap_2.width()*0.5,//矩形宽度。0.5表示显示区域为原图的一半大
			pixmap_2.height()*0.5)//矩形高度。0.5表示显示区域为原图的一半大

第五步:写字

//第一行,空白
    int lineIndex = 0; //虚拟行号:用于控制在纸上的纵坐标
    lineIndex++;
    //第二行,居中显示总标题(加粗显示)
    QPen tmppen = ori_pen;
    tmppen.setWidth(ori_pen.width()*3);
    tmppen.setColor(Qt::darkYellow);
    painter.setPen(tmppen);
    painter.drawText(paperStartX, paperStartY + (lineIndex++) * lineHeight, paperWidth, lineHeight, Qt::AlignCenter, "Test Title");
    //第3行:空一行
    lineIndex++;
    //第4行,,,,
    //TO DO....

drawText参数说明:

inline void QPainter::drawText(int x, int y, int w, int h, int flags, const QString &str, QRect *br)
//x:开始写字区域矩形的左上角X坐标
//y:开始写字区域矩形的左上角Y坐标
//w:开始写字区域矩形的宽度
//h:开始写字区域矩形的高度
//flags:用于设置对齐方式等等
//str:想要写的内容
//br:我不知道,没管它。嘻嘻

//QT的源码原型
inline void QPainter::drawText(int x, int y, int w, int h, int flags, const QString &str, QRect *br)
{
    drawText(QRect(x, y, w, h), flags, str, br);
}

第五步:画表格

 //将纸张分为7列,共需8条竖线
    int columnCnt = 7;
    int columnWidth =(int)(paperWidth*1.0 / columnCnt + 0.5);
    paperStartY += 5*lineHeight; //前面五行为其它内容,之后才是表格。
    int rowCnt = 32 + 1; //表格总行数,外加第一行为标题。
    for(int i = 0; i < columnCnt + 1; i++)
    {
        painter.drawLine(paperStartX + columnWidth*i, paperStartY, paperStartX + columnWidth*i, paperStartY + rowCnt*lineHeight);
    }
    //表格有33行,需要33条横线
    for(int i = 0; i < rowCnt + 1; i++)
    {
        painter.drawLine(paperStartX , paperStartY + i*lineHeight, paperStartX + paperWidth, paperStartY + i*lineHeight);
    }

    //先把第一行的表头填充完毕
    painter.setPen(tmppen);
    QString tableHeader[] = {"姓名", "性别", "院系-班级", "挂科数量", "谈恋爱次数", "逃课数量", "是否好学生"};
    for(int i = 0; i < columnCnt; i++)
    {
        painter.drawText(QRect(paperStartX + columnWidth*i, paperStartY, columnWidth, lineHeight), Qt::AlignCenter, tableHeader[i]);
    }
    painter.setPen(ori_pen);
    //填写完毕表头后,画笔的起始Y再往下移动一个行高。
    paperStartY += lineHeight;

	//填写表格内容......略
	//使用drawText(QRect(x, y, w, h), flags, str, br);函数原型去填充每个小格子去吧。注意坐标的换算就行!

第最后一步:画家结束创作。打印机也完成打印。

painter.end();//画家绘制结束,与此同时,pdf也绘制完成。

本文标签: 文件QTPDF