Qt 报表实现 -QPainter + QPrinter

QPainter 是可以在 QPrinter 上绘制图形和文字的,利用这个方法,可以绘制任何图形或者文字、表格等,可以实现复杂的表格绘制,如果报表比较特殊,可以尝试使用这个方法,下面简单介绍一下实现的过程。

 

报表绘制

实现简介

我这边里封装了一个报表打印类,用于打印报表,当前并没有传入数据和参数,实际实际项目是需要传入参数和数据的。

 

首先是打印的接口代码:

 

1    void printWithPreview();
2    void printDirect();
3    void printOnePage(QPainter *painter, int no);

 

printWithPreview 是用于调出打印预览窗口;


printDirect 是直接打印

printOnePage 是打印一页;因为可能会打印多个页,所以这里把一页的绘制单独封装为一个函数

 

打印信号处理槽函数,用于接收打印信号,在这个函数里调用 printOnePage 去绘制要打印的报表。

 

1    void printDocument(QPrinter *printer);

 

打印版式设置

横向打印和纵向打印;


打印方向 Portrait 纵向,Landscape:横向


使用如下函数设置

 

1enum Orientation { Portrait, Landscape };
2void setOrientation(Orientation);

 

代码

头文件:

 

 1#ifndef CTESTREPORT_H
 2#define CTESTREPORT_H
 3
 4#include 
 5#include 
 6#include 
 7#include 
 8#include 
 9
10class CTestReport:public QObject
11{
12    Q_OBJECT
13public:
14    explicit CTestReport(QObject *parent = nullptr);
15    virtual ~CTestReport();
16
17
18
19    void printWithPreview();
20    void printDirect();
21    void printOnePage(QPainter *painter, int no);
22
23private:
24    void drawTable(QPainter *painter, int no);
25signals:
26
27public slots:
28
29private slots:
30    void printDocument(QPrinter *printer);
31
32private:
33
34    int m_startx;    // 整体表格在 A4 纸中的起始 x 坐标
35    int m_starty;    // 整体表格在 A4 纸中的起始 y 坐标
36    int m_width;     // 整体表格的宽
37    int m_height;    // 整体表格的高
38
39    int m_titleHeight;    // 标题栏的高
40
41    int m_colNum ;   // 表格的总列数
42    int m_rowNum ;   // 表格的总行数
43    int m_rowHeight; // 单元表格高
44    int m_colWidth;  // 单元表格宽
45
46};
47
48
49#endif // CTESTREPORT_H

 

类实现源文件:

 

  1#include 
  2#include 
  3#include 
  4#include 
  5#include 
  6#include 
  7#include 
  8#include "ctestreport.h"
  9
 10CTestReport::CTestReport(QObject *parent)
 11{
 12    m_startx = 30;
 13    m_starty = 30;
 14    m_width  = 720;   // 试出来的尺寸像素点
 15    m_height = 1035;
 16
 17    m_titleHeight = 35;
 18
 19    m_colNum = 10;            // 初始化
 20    m_rowNum = 40;           // 计算表格的行数
 21    m_colWidth = m_width / m_colNum;
 22    m_rowHeight= m_height / m_rowNum;
 23
 24}
 25
 26CTestReport::~CTestReport()
 27{
 28
 29}
 30
 31void CTestReport::printWithPreview()
 32{
 33    QPrinter printer(QPrinter::ScreenResolution);
 34    printer.setPageSize(QPrinter::A4);
 35    printer.setOrientation(QPrinter::Portrait); // 打印方向 Portrait 纵向,Landscape:横向
 36//    printer.setOutputFormat(QPrinter::NativeFormat);
 37    QPrintPreviewDialog preview(&printer);
 38    connect(&preview, SIGNAL(paintRequested(QPrinter*)), this, SLOT(printDocument(QPrinter*)));
 39    preview.setWindowState(Qt::WindowMaximized);
 40    preview.exec();
 41}
 42
 43void CTestReport::printDirect()
 44{
 45    QPrinter printer(QPrinter::ScreenResolution);
 46    printer.setPageSize(QPrinter::A4);
 47    QPrintDialog printDialog(&printer);
 48    printer.setOrientation(QPrinter::Portrait); // 打印方向
 49
 50    if (printDialog.exec() == QDialog::Accepted)
 51    {
 52        printDocument(&printer);
 53    }
 54}
 55
 56
 57void CTestReport::drawTable(QPainter *painter, int no)
 58{
 59    // 调整表格整体的高度
 60
 61    // 总框体
 62    painter->drawRect(m_startx,m_starty,m_width,m_height);
 63    // 标题栏
 64    painter->drawLine(m_startx,m_starty+m_titleHeight,m_startx+m_width,m_starty+m_titleHeight);
 65    painter->setFont(QFont("宋体", 20));
 66    painter->drawText(QRect(m_startx,m_starty+3,m_width,m_titleHeight), Qt::AlignCenter, QString("测试报表%1").arg(no));
 67    painter->drawLine(m_startx,m_starty+m_height,m_startx+m_width,m_starty+m_height);
 68
 69
 70    int x1,y1,x2,y2;
 71
 72    painter->setFont(QFont("宋体", 10));
 73    // 绘制表格列单元线
 74    for (int i = 1; i < m_colNum; i++)
 75    {
 76        x1 = m_startx + m_colWidth*i;
 77        y1 = m_startx + m_titleHeight;
 78        x2 = m_startx + m_colWidth*i;
 79        y2 = m_starty + m_height;
 80        painter->drawLine(x1, y1, x2, y2);
 81
 82        painter->drawText(QRectF(x1,y1,m_colWidth,m_rowHeight), Qt::AlignCenter, QString("%1 列").arg(i));
 83    }
 84
 85
 86    // 第一行为序号
 87    for (int rowNo = 1; rowNo <= m_rowNum; rowNo++)
 88    {
 89        x1 = m_startx;
 90        y1 = m_starty+m_titleHeight + m_rowHeight*rowNo;
 91        x2 = m_startx + m_width;
 92        y2 = m_starty+m_titleHeight + m_rowHeight*rowNo;
 93
 94        // 标题
 95        if (rowNo > 1)
 96        painter->drawText(QRect(x1,y1-m_rowHeight, m_colWidth,m_rowHeight), Qt::AlignCenter, QString("%1").arg(rowNo-1));
 97
 98
 99        // 行线
100        if ( rowNo == m_rowNum) // 最后一行不划线
101        {
102            break;
103        }
104
105        painter->drawLine(x1, y1, x2, y2);
106    }
107
108    // 表最下面的备注
109    painter->drawText(QRect(m_startx,m_starty+m_height+2,450,25), Qt::AlignLeft, "注:测试报表备注信息。");
110
111    // 制表时间 2020-12-28
112    QString dateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
113    painter->drawText(QRect(m_startx+m_width-200,m_starty+m_height+2,200,m_rowHeight), Qt::AlignRight, "制表时间:"+dateTime);
114
115}
116
117void CTestReport::printDocument(QPrinter *printer)
118{
119    QPainter painter;
120
121    painter.begin(printer);
122
123    painter.setPen(Qt::black);
124
125    for (int i = 0; i < 5; i++)
126    {
127        printOnePage(&painter,i+1);
128
129        if ( i != 4 ) // 判断是否最后一页,如果不是最后一页则新建一页
130        {
131            printer->newPage(); // 新建页
132            painter.setPen(Qt::black);
133        }
134    }
135
136    painter.end();
137}
138
139void CTestReport::printOnePage(QPainter *painter, int no)
140{
141//    qDebug()<<"reportInfo title: "<getTitle();
142
143    // 正常使用 painter 绘制文字、pixmap 等在 printer 上
144
145    drawTable(painter,no);
146
147
148}

 

测试调用代码,我是放到一个按键的槽函数里调用的:

 

1void MainWindow::on_btnReport_clicked()
2{
3    CTestReport reporter;
4
5    reporter.printWithPreview();
6
7}

 

效果

 

效果