├── LICENSE
├── QTableViewPrinter
├── example
│ ├── TablePrintExample.pro
│ ├── TablePrintExample.pro.user
│ ├── main.cpp
│ ├── widget.cpp
│ ├── widget.h
│ └── widget.ui
├── qtableviewprinter.cpp
└── qtableviewprinter.h
├── README.md
└── images
├── 1.png
├── 2.png
├── 3.png
├── 4.png
└── 5.png
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018, tonyonce
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/QTableViewPrinter/example/TablePrintExample.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2016-03-16T18:21:24
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core gui printsupport sql
8 |
9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 |
11 | TARGET = example
12 | TEMPLATE = app
13 |
14 |
15 | SOURCES += main.cpp\
16 | widget.cpp \
17 | ../qtableviewprinter.cpp
18 |
19 | HEADERS += widget.h \
20 | ../qtableviewprinter.h
21 |
22 | FORMS += widget.ui
23 |
--------------------------------------------------------------------------------
/QTableViewPrinter/example/TablePrintExample.pro.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | EnvironmentId
7 | {5fe2768e-6359-41dc-a2a5-de910109f03a}
8 |
9 |
10 | ProjectExplorer.Project.ActiveTarget
11 | 0
12 |
13 |
14 | ProjectExplorer.Project.EditorSettings
15 |
16 | true
17 | false
18 | true
19 |
20 | Cpp
21 |
22 | CppGlobal
23 |
24 |
25 |
26 | QmlJS
27 |
28 | QmlJSGlobal
29 |
30 |
31 | 2
32 | UTF-8
33 | false
34 | 4
35 | false
36 | 80
37 | true
38 | true
39 | 1
40 | true
41 | false
42 | 0
43 | true
44 | true
45 | 0
46 | 8
47 | true
48 | 0
49 | true
50 | true
51 | true
52 | false
53 |
54 |
55 |
56 | ProjectExplorer.Project.PluginSettings
57 |
58 |
59 |
60 | ProjectExplorer.Project.Target.0
61 |
62 | Desktop Qt 5.6.1 MinGW 32bit
63 | Desktop Qt 5.6.1 MinGW 32bit
64 | qt.56.win32_mingw49_kit
65 | 0
66 | 0
67 | 0
68 |
69 | D:/Liucheng/Qt/project/QtTablePrinter/Qt-Table-Printer/qdebug
70 |
71 |
72 | true
73 | qmake
74 |
75 | QtProjectManager.QMakeBuildStep
76 | true
77 |
78 | false
79 | false
80 | false
81 |
82 |
83 | true
84 | Make
85 |
86 | Qt4ProjectManager.MakeStep
87 |
88 | false
89 |
90 |
91 |
92 | 2
93 | 构建
94 |
95 | ProjectExplorer.BuildSteps.Build
96 |
97 |
98 |
99 | true
100 | Make
101 |
102 | Qt4ProjectManager.MakeStep
103 |
104 | true
105 | clean
106 |
107 |
108 | 1
109 | 清理
110 |
111 | ProjectExplorer.BuildSteps.Clean
112 |
113 | 2
114 | false
115 |
116 | Debug
117 |
118 | Qt4ProjectManager.Qt4BuildConfiguration
119 | 2
120 | true
121 |
122 | 1
123 |
124 |
125 | 0
126 | 部署
127 |
128 | ProjectExplorer.BuildSteps.Deploy
129 |
130 | 1
131 | 在本地部署
132 |
133 | ProjectExplorer.DefaultDeployConfiguration
134 |
135 | 1
136 |
137 |
138 | false
139 | false
140 | 1000
141 |
142 | true
143 |
144 | false
145 | false
146 | false
147 | false
148 | true
149 | 0.01
150 | 10
151 | true
152 | 1
153 | 25
154 |
155 | 1
156 | true
157 | false
158 | true
159 | valgrind
160 |
161 | 0
162 | 1
163 | 2
164 | 3
165 | 4
166 | 5
167 | 6
168 | 7
169 | 8
170 | 9
171 | 10
172 | 11
173 | 12
174 | 13
175 | 14
176 |
177 | 2
178 |
179 | TablePrintExample
180 |
181 | Qt4ProjectManager.Qt4RunConfiguration:D:/Liucheng/Qt/project/QtTablePrinter/Qt-Table-Printer/example/TablePrintExample.pro
182 | true
183 |
184 | TablePrintExample.pro
185 | false
186 |
187 | D:/Liucheng/Qt/project/QtTablePrinter/Qt-Table-Printer/qdebug
188 | 3768
189 | false
190 | true
191 | false
192 | false
193 | true
194 |
195 | 1
196 |
197 |
198 |
199 | ProjectExplorer.Project.TargetCount
200 | 1
201 |
202 |
203 | ProjectExplorer.Project.Updater.FileVersion
204 | 18
205 |
206 |
207 | Version
208 | 18
209 |
210 |
211 |
--------------------------------------------------------------------------------
/QTableViewPrinter/example/main.cpp:
--------------------------------------------------------------------------------
1 | #include "widget.h"
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | QApplication a(argc, argv);
7 | Widget w;
8 | w.show();
9 |
10 | return a.exec();
11 | }
12 |
--------------------------------------------------------------------------------
/QTableViewPrinter/example/widget.cpp:
--------------------------------------------------------------------------------
1 | #include "widget.h"
2 | #include "ui_widget.h"
3 | #include "../qtableviewprinter.h"
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | Widget::Widget(QWidget* parent) :
15 | QWidget(parent),
16 | ui(new Ui::Widget) {
17 | ui->setupUi(this);
18 | initDb();
19 | model = new QSqlTableModel;
20 | model->setTable("exampleTable");
21 | model->select();
22 | ui->tableView->setModel(model);
23 | }
24 |
25 | Widget::~Widget() {
26 | delete ui;
27 | delete model;
28 | }
29 |
30 | void Widget::print(QPrinter *printer)
31 | {
32 | //定义纸张属性
33 | printer->setPageSize(QPrinter::A4);
34 | //申明画笔
35 | QPainter painter;
36 | if(!painter.begin(printer)) {
37 | qWarning() << "开启打印失败!";
38 | return;
39 | }
40 | //申明tablePrinter
41 | QTableViewPrinter tablePrinter(&painter, printer);
42 | QVector colWidth;
43 | for(int i=0;itableView->model()->columnCount();++i){
44 | colWidth.push_back(ui->tableView->columnWidth(i));
45 | }
46 |
47 | //设定字体
48 | QFont headerFont;
49 | headerFont.setBold(true);
50 | QFont contentFont;
51 | contentFont.setPointSize(15);
52 | tablePrinter.setContentFont(contentFont);
53 |
54 | //设定标题
55 | PageTitle* title=new PageTitle(&painter,printer);
56 | title->setPageTitle("表格打印测试实例");
57 | tablePrinter.setPagerTitle(title);
58 | tablePrinter.setTitleFlag(TitleFlag::EVERY_PAGE);
59 |
60 | //设定页脚
61 | PageFooter* pagefooter=new PageFooter(&painter);
62 | pagefooter->setCreater("系统管理员");
63 | tablePrinter.setPagerFooter(pagefooter);
64 |
65 | QStringList headers = { "标题0" , "标题1|内容1" , "标题2|内容2" , "标题2|内容3"};
66 | QStringList headers2 = { "标题0" , "标题1|内容1" , "标题2|内容2" , "标题2|内容3"};
67 | if(!tablePrinter.printTable(ui->tableView, headers, headers2)) {
68 | qDebug() << tablePrinter.lastError();
69 | }
70 | painter.end();
71 | }
72 |
73 | void Widget::initDb() {
74 | QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
75 | db.setDatabaseName("exampleDb");
76 | if(!db.open()) {
77 | qWarning() << "can't open db" << db.lastError().text();
78 | }
79 | QSqlQuery query;
80 | query.exec("CREATE TABLE IF NOT EXISTS exampleTable(number int, b TEXT, c TEXT, d TEXT);");
81 | query.exec("DELETE FROM exampleTable;");
82 | QSqlDatabase::database().transaction();
83 | for(int i = 1; i < 21; i++) {
84 | query.exec(QString("INSERT INTO exampleTable VALUES (%1, '%2', '%3', '%4');")
85 | .arg(i).arg("column2").arg("column3").arg("column4"));
86 | }
87 | QSqlDatabase::database().commit();
88 | }
89 |
90 | void Widget::on_pushButton_clicked()
91 | {
92 | QPrintPreviewDialog dialog;
93 | connect(&dialog, SIGNAL(paintRequested(QPrinter*)), this, SLOT(print(QPrinter*)));
94 | dialog.exec();
95 | }
96 |
--------------------------------------------------------------------------------
/QTableViewPrinter/example/widget.h:
--------------------------------------------------------------------------------
1 | #ifndef WIDGET_H
2 | #define WIDGET_H
3 |
4 | #include
5 |
6 | class QPrinter;
7 | class QSqlTableModel;
8 |
9 | namespace Ui {
10 | class Widget;
11 | }
12 |
13 | class Widget : public QWidget {
14 | Q_OBJECT
15 |
16 | public:
17 | explicit Widget(QWidget* parent = 0);
18 | ~Widget();
19 |
20 | private:
21 | Ui::Widget* ui;
22 | void initDb();
23 | QSqlTableModel *model;
24 | private slots:
25 | void print(QPrinter *printer);
26 | void on_pushButton_clicked();
27 | };
28 |
29 | #endif // WIDGET_H
30 |
--------------------------------------------------------------------------------
/QTableViewPrinter/example/widget.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Widget
4 |
5 |
6 |
7 | 0
8 | 0
9 | 520
10 | 359
11 |
12 |
13 |
14 | 表格打印测试
15 |
16 |
17 | -
18 |
19 |
20 | -
21 |
22 |
-
23 |
24 |
25 | Qt::Horizontal
26 |
27 |
28 |
29 | 40
30 | 20
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 | 打印测试
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/QTableViewPrinter/qtableviewprinter.cpp:
--------------------------------------------------------------------------------
1 | #include "qtableviewprinter.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | //--------主体内容-------------
8 | int QTableViewPrinter::headerHeight = 100;
9 | int QTableViewPrinter::leftBlank = 40;
10 | int QTableViewPrinter::rightBlank = 40;
11 |
12 | QTableViewPrinter::QTableViewPrinter(QPainter* painter, QPrinter* printer) : painter(painter),printer(printer) {
13 | //设定默认值
14 | topMargin = 3;
15 | bottomMargin = 3;
16 | leftMargin = 3;
17 | rightMargin = 3;
18 | bottomHeight = 40;
19 | maxRowHeight = 1000;
20 | mheaderRowHeight = 0;
21 | pen = painter->pen();
22 | headersFont = QFont("宋体",9);
23 | contentFont = QFont("宋体",9);
24 | headerColor = painter->pen().color();
25 | contentColor = painter->pen().color();
26 | pageFooter = NULL;
27 | pageHeader = NULL;
28 | pageTitle = NULL;
29 | error = "无错误";
30 | mheaderFlag = true;
31 | textLineFlag=Qt::TextFlag::TextSingleLine;
32 | textAlign=Qt::AlignmentFlag::AlignCenter;
33 | titleFlag=TitleFlag::EVERY_PAGE;
34 | }
35 |
36 | bool QTableViewPrinter::printTable(QTableView *tableView, const QStringList &totalFields, const QStringList &visualFields)
37 | {
38 | //初始化
39 | mTableView = tableView;
40 | mHeaderTitles = totalFields;
41 | model = tableView->model();
42 | //错误检查
43 | if(!printer->isValid()) {
44 | error = "打印指针有误!";
45 | return false;
46 | }
47 | if(!painter->isActive()) {
48 | error = "画笔指针有误!";
49 | return false;
50 | }
51 | if(!setPrintColumnList(visualFields))
52 | return false;
53 | //开始绘制
54 | if(!paintTable(0,0,true))
55 | return false;
56 | return true;
57 | }
58 |
59 | QString QTableViewPrinter::lastError() {
60 | return error;
61 | }
62 |
63 | void QTableViewPrinter::setCellMargin(int left, int right, int top, int bottom) {
64 | topMargin = top;
65 | bottomMargin = bottom;
66 | leftMargin = left;
67 | rightMargin = right;
68 | }
69 |
70 | void QTableViewPrinter::setPageMargin(int left, int right, int top, int bottom) {
71 | headerHeight = top;
72 | bottomHeight = bottom;
73 | leftBlank = left;
74 | rightBlank = right;
75 | }
76 |
77 | void QTableViewPrinter::setPageHeader(PageHeader *pageheader)
78 | {
79 | pageHeader=pageheader;
80 | }
81 |
82 | void QTableViewPrinter::setPagerFooter(PageFooter *pagefooter)
83 | {
84 | pageFooter = pagefooter;
85 | }
86 |
87 | void QTableViewPrinter::setPagerTitle(PageTitle *pagetitle)
88 | {
89 | pageTitle = pagetitle;
90 | }
91 |
92 | void QTableViewPrinter::setPen(QPen p) {
93 | pen = p;
94 | }
95 |
96 | void QTableViewPrinter::setHeadersFont(QFont f) {
97 | headersFont = f;
98 | }
99 |
100 | void QTableViewPrinter::setContentFont(QFont f) {
101 | contentFont = f;
102 | }
103 |
104 | void PageHeader::setPageHeaderFont(QFont font)
105 | {
106 | pageHeaderFont=font;
107 | }
108 |
109 | void PageFooter::setViewFlag(bool zbr, bool ym, bool zbsj)
110 | {
111 | mzbr = zbr;
112 | mym = ym;
113 | mzbsj = zbsj;
114 | }
115 |
116 | void QTableViewPrinter::setTextWordWrap(Qt::TextFlag Wrap)
117 | {
118 | textLineFlag=Wrap;
119 | }
120 |
121 | void QTableViewPrinter::setHeaderColor(QColor color) {
122 | headerColor = color;
123 | }
124 |
125 | void QTableViewPrinter::setContentColor(QColor color) {
126 | contentColor = color;
127 | }
128 |
129 | void QTableViewPrinter::setMaxRowHeight(int height) {
130 | maxRowHeight = height;
131 | }
132 |
133 | void QTableViewPrinter::setTextAlign(Qt::AlignmentFlag align)
134 | {
135 | textAlign=align;
136 | }
137 |
138 | void QTableViewPrinter::setTitleFlag(const TitleFlag type)
139 | {
140 | titleFlag = type;
141 | }
142 |
143 | void QTableViewPrinter::setHeaderFlag(bool flag)
144 | {
145 | mheaderFlag = flag;
146 | }
147 |
148 | void QTableViewPrinter::position(const QString &str)
149 | {
150 | qDebug()<transform().dx()<<" y:"<transform().dy();
151 | }
152 |
153 | bool QTableViewPrinter::setPrintColumnList(const QStringList &list)
154 | {
155 | if(list.size()==0 || mHeaderTitles.size()==0 || model->columnCount()==0)
156 | return false;
157 | mColumnList.clear();
158 | //先给行号赋值
159 | if(!list.contains("行号")){
160 | PrintColumn *item= new PrintColumn();
161 | item->name="行号";
162 | item->modelColumn=-1;
163 | item->columnWidth=50;
164 | mColumnList.push_back(item);
165 | }
166 | for(int i=0;icolumnCount();++i){
167 | if(list.contains(mHeaderTitles.at(i))){
168 | PrintColumn *item= new PrintColumn();
169 | item->name= mHeaderTitles.at(i);
170 | item->modelColumn = i;
171 | item->columnWidth = mTableView->columnWidth(i)*1.4*contentFont.pointSize()/12+leftMargin+rightMargin;
172 | if(item->name.contains("|")){//复杂表头
173 | QString temp=item->name;
174 | QStringList tempList=temp.split("|");
175 | mergeColumn* merge;
176 | for(int j=0;j0){
178 | if(_mergeColumnHash[j].last()->text!=tempList.at(j)){
179 | merge = new mergeColumn();
180 | merge->text = tempList.at(j);
181 | merge->columnList.push_back(QString::number(i));
182 | _mergeColumnHash[j].push_back(merge);
183 | }else{//需合并的列
184 | if(j==0){
185 | merge = _mergeColumnHash[j].last();
186 | merge->columnList.push_back(QString::number(i));
187 | }else{
188 | if(_mergeColumnHash[j-1].last()->columnList.contains(QString::number(i)) && _mergeColumnHash[j-1].last()->columnList.contains(_mergeColumnHash[j].last()->columnList.last())){
189 | merge = _mergeColumnHash[j].last();
190 | merge->columnList.push_back(QString::number(i));
191 | }else{
192 | merge = new mergeColumn();
193 | merge->text = tempList.at(j);
194 | merge->columnList.push_back(QString::number(i));
195 | _mergeColumnHash[j].push_back(merge);
196 | }
197 | }
198 | }
199 | }else{
200 | merge = new mergeColumn();
201 | merge->text = tempList.at(j);
202 | merge->columnList.push_back(QString::number(i));
203 | _mergeColumnHash[j].push_back(merge);
204 | }
205 | }
206 | }
207 | mColumnList.push_back(item);
208 | }
209 | }
210 | return true;
211 | }
212 |
213 | bool QTableViewPrinter::paintTable(int row, int column, bool headFlag)
214 | {
215 | //获取总行数,列数
216 | int rowCount = model->rowCount();
217 | int columnCount=mColumnList.size();
218 | //界面宽度,高度
219 | int viewWidth = painter->viewport().width();
220 | int viewHeight = painter->viewport().height();
221 | //表格宽度,高度
222 | int tableWidth = viewWidth - leftBlank - rightBlank;
223 | int tableHeight = viewHeight - headerHeight - bottomHeight;
224 | //绘制的最后一行,一列
225 | int lastRow =0 ,lastColumn = 0;
226 | //当前页实际总宽度及每一列宽度
227 | int realTableWidth = 0;
228 | bool ischild=false;
229 | QList columnWidth;
230 | for(int i=column;icolumnWidth;
233 | if(realTableWidth+width > tableWidth){
234 | lastColumn = i;
235 | break;
236 | }
237 | columnWidth.push_back(width);
238 | realTableWidth += width;
239 | }
240 | //当前绘制页的总列数
241 | int curColumnCount = columnWidth.size();
242 | //是否绘制表格头
243 | bool curheadflag=headFlag;
244 | //设置原点
245 | painter->translate(-painter->transform().dx(),-painter->transform().dy()+headerHeight);//(0,60)
246 | painter->save();//(0,60)
247 |
248 | //绘制页眉
249 | if(pageHeader){
250 | painter->save();
251 | pageHeader->startDrawHeader();
252 | painter->restore();
253 | }
254 | //绘制标题
255 | if(pageTitle){
256 | painter->save();
257 | pageTitle->startDrawTitle();
258 | painter->restore();
259 | }
260 | //绘制页脚
261 | if(pageFooter) {
262 | painter->save();
263 | painter->translate(-painter->transform().dx(), -painter->transform().dy());
264 | pageFooter->startDrawFooter();
265 | painter->restore();
266 | }
267 |
268 | //定位表格左顶点
269 | painter->translate(-painter->transform().dx() + leftBlank, 0);
270 | painter->save();//(40,60)
271 |
272 | painter->setPen(pen);
273 | //水平顶线
274 | painter->drawLine(0, 0, realTableWidth, 0);
275 |
276 | //先用一个测试painter获取最大行高
277 | QPainter testSize;
278 | QImage* image = new QImage(10, 10, QImage::Format_RGB32);
279 | image->setDotsPerMeterX(printer->logicalDpiX() * 100 / 2.54); // 2.54 cm = 1 inch
280 | image->setDotsPerMeterY(printer->logicalDpiY() * 100 / 2.54);
281 | testSize.begin(image);
282 |
283 | //获取行高
284 | int i;
285 | if(curheadflag)
286 | i = row-1;
287 | else
288 | i = row;
289 | testSize.setFont(headersFont);
290 | painter->setFont(headersFont);
291 | int currentPageRowCount=0;
292 | QHash headrowheight;
293 | for(i; isetFont(contentFont);
299 | }
300 |
301 | QString str;
302 | if(iname;
304 | }else{
305 | if(mColumnList.at(j)->modelColumn==-1){//行号
306 | str = QString::number(i+1);
307 | }else
308 | str = model->data(model->index(i,mColumnList.at(j)->modelColumn), Qt::DisplayRole).toString();
309 | }
310 |
311 | if(str.contains("|")){
312 | int height=0;
313 | QStringList list=str.split("|");
314 | for(int k=0;kcolumnWidth- rightMargin - leftMargin, maxRowHeight);
316 | QRect realRect;
317 | testSize.drawText(rect, textAlign | textLineFlag, list.at(k), &realRect);
318 | if(headrowheight[k] maxHeight && mColumnList.at(j)->columnWidth != 0){
323 | height > maxRowHeight ? maxHeight = maxRowHeight : maxHeight = height;
324 | }
325 | }else{
326 | QRect rect(0, 0, mColumnList.at(j)->columnWidth- rightMargin - leftMargin, maxRowHeight);
327 | QRect realRect;
328 | testSize.drawText(rect, textAlign | textLineFlag, str, &realRect);
329 | if (realRect.height() > maxHeight && mColumnList.at(j)->columnWidth != 0) {
330 | realRect.height() > maxRowHeight ? maxHeight = maxRowHeight : maxHeight = realRect.height();
331 | }
332 | }
333 | }
334 | //表格头高度
335 | if(mheaderRowHeight==0){
336 | mheaderRowHeight = maxHeight;
337 | }
338 | //判断是否新增一页
339 | double curHeight=painter->transform().dy() + maxHeight + topMargin + bottomMargin;
340 | double topHeight=painter->viewport().height() -bottomHeight;
341 | if(curHeight > topHeight){
342 | lastRow = i;
343 | //-------绘制当前页垂直线----------
344 | int y = painter->transform().dy();
345 | painter->restore();//(40,60)
346 | painter->save();//(40,60)
347 | for(int j = column; j < column+curColumnCount; j++) {
348 | if(j==column){
349 | painter->translate(0, -painter->transform().dy()+headerHeight);
350 | }else{
351 | painter->translate(0,-painter->transform().dy()+headerHeight+mheaderRowHeight+topMargin+bottomMargin);
352 | }
353 | painter->drawLine(0, 0, 0, - painter->transform().dy() + y);
354 | painter->translate(mColumnList.at(j)->columnWidth, 0);
355 | }
356 | painter->translate(0, -painter->transform().dy()+headerHeight);
357 | painter->drawLine(0, 0, 0, - painter->transform().dy() + y);
358 | painter->restore();//(40,60)
359 | //------结束绘制当前页垂直线---------
360 | //新建子页
361 | printer->newPage();
362 | paintTable(lastRow,column,mheaderFlag);
363 | painter->save();//(40,60)
364 | ischild=true;
365 | break;
366 | }
367 | //-------------开始绘制表格数据----------------------
368 | painter->save(); //(40,60)
369 | i < row ? painter->setPen(QPen(headerColor)) : painter->setPen(QPen(contentColor));
370 | curheadflag ? painter->setFont(headersFont) : painter->setFont(contentFont);
371 | int firstc = mColumnList.at(column)->modelColumn;
372 | int lastc = mColumnList.at(column+curColumnCount-1)->modelColumn;
373 | //绘制数据
374 | for(int j = column; j < column+curColumnCount; j++) {
375 | QString str;
376 | if(curheadflag) {
377 | str = mColumnList.at(j)->name;
378 | } else {
379 | if(mColumnList.at(j)->modelColumn==-1){
380 | str = QString::number(i+1);
381 | }else
382 | str = model->data(model->index(i,mColumnList.at(j)->modelColumn), Qt::DisplayRole).toString();
383 | }
384 |
385 | if(str.contains("|")){
386 | QStringList templist = str.split("|");
387 | int realHeight=0;
388 | for(int a=0;amodelColumn;
401 | int width=0;
402 | //查找当前列, 计算列宽
403 | for(int b=0;b<_mergeColumnHash[a].size();++b){
404 | //取容器列
405 | mergeColumn* item = _mergeColumnHash[a].at(b);
406 | //判断容器列是否存在当前列
407 | if(item->columnList.contains(QString::number(curc))){
408 | //循环容器列, 找到列位置, 获取列宽
409 | if(item->columnList.at(0).toInt()==curc || curc==firstc){
410 | int d=0;
411 | for(int c=0;ccolumnList.size();++c){
412 | //要求容器列第一个列数值等于当前列或者容器列或者当前页第一列值在容器列中间
413 | if(item->columnList.at(c).toInt()<=lastc && item->columnList.at(c).toInt()>=curc){
414 | width += mColumnList.at(j+d)->columnWidth;
415 | d++;
416 | }
417 | }
418 | }
419 | break;
420 | }
421 | }
422 | //判断列宽
423 | if(width==0){//当前列所在的标题已经绘制过了, 无需再绘制
424 | if(a==templist.size()-1){//换列
425 | painter->translate(mColumnList.at(j)->columnWidth, -painter->transform().dy()+headerHeight);
426 | }else{//不绘制换行
427 | painter->translate(0, realHeight+bottomMargin+topMargin);
428 | }
429 | }else{//准备绘制
430 | QRect rec(leftMargin, topMargin, width - rightMargin - leftMargin, realHeight);
431 | painter->drawText(rec, textAlign | textLineFlag, temp);
432 | //绘制横线
433 | if(a!=templist.size()-1){//最后一行无需绘制
434 | painter->drawLine(0,realHeight+bottomMargin+topMargin,width,realHeight+bottomMargin+topMargin);
435 | }
436 | //绘制竖线
437 | painter->drawLine(width,0,width,realHeight+bottomMargin+topMargin);
438 |
439 | if(a==templist.size()-1){//换列
440 | painter->translate(mColumnList.at(j)->columnWidth, -painter->transform().dy()+headerHeight);
441 | }else{//换行
442 | painter->translate(0, realHeight+bottomMargin+topMargin);
443 | }
444 | }
445 | }
446 | }else{
447 | QRect rec(leftMargin, topMargin, mColumnList.at(j)->columnWidth - rightMargin - leftMargin, maxHeight);
448 | painter->drawText(rec, textAlign | textLineFlag, str);
449 | //绘制竖线
450 | painter->drawLine(mColumnList.at(j)->columnWidth,0,mColumnList.at(j)->columnWidth,maxHeight+bottomMargin+topMargin);
451 | painter->translate(mColumnList.at(j)->columnWidth, 0);
452 | }
453 | }
454 | if(curheadflag){
455 | curheadflag = false;
456 | }
457 | painter->restore(); //(40,60)
458 | //--------------结束绘制表格数据-----------------------
459 | //绘制当前行横线
460 | painter->drawLine(0, maxHeight + topMargin + bottomMargin, realTableWidth,maxHeight + topMargin + bottomMargin);
461 | //更新坐标
462 | painter->translate(0, maxHeight + topMargin + bottomMargin);
463 | currentPageRowCount++;
464 | }
465 | //-----------绘制垂直线--------------------
466 | int y = painter->transform().dy();
467 | painter->restore();//(40,60)
468 | if(!ischild){ //垂直线已在子页中绘制过, 无需重复再绘制
469 | for(int i = column; i < column+curColumnCount; i++) {
470 | if(i==column){
471 | painter->translate(0, -painter->transform().dy()+headerHeight);
472 | }else{
473 | painter->translate(0,-painter->transform().dy()+headerHeight+mheaderRowHeight+topMargin+bottomMargin);
474 | }
475 | painter->drawLine(0, 0, 0,- painter->transform().dy() + y);
476 | painter->translate(mColumnList.at(i)->columnWidth, 0);
477 | }
478 | painter->translate(0, -painter->transform().dy()+headerHeight);
479 | painter->drawLine(0, 0, 0, - painter->transform().dy() + y);
480 | }
481 | //-----------垂直线绘制完毕----------------
482 | testSize.end();
483 | delete image;
484 |
485 | //恢复原点(0,60)
486 | painter->restore();
487 |
488 | //分页(只有第一页的数据允许分页)
489 | if(column+curColumnCountnewPage();
491 | paintTable(row,lastColumn,mheaderFlag);
492 | }
493 | return true;
494 | }
495 | //--------主体内容结束-------------
496 |
497 | //--------页眉类----------------
498 | PageHeader::PageHeader(QPainter *painter)
499 | {
500 | mpainter = painter;
501 | pageHeaderFont = QFont("Microsoft YaHei",9);
502 | }
503 |
504 | void PageHeader::startDrawHeader()
505 | {
506 |
507 | }
508 | //--------页眉类结束-------------
509 |
510 |
511 | //--------页脚类-------------
512 | int PageFooter::pageNumber=1;
513 |
514 | PageFooter::PageFooter(QPainter *painter)
515 | {
516 | mpainter = painter;
517 | creater = "无";
518 | pageFooterFont = QFont("宋体",9);
519 | mzbr = true;
520 | mzbsj = true;
521 | mym = true;
522 | }
523 |
524 | void PageFooter::setPageFooterFont(QFont font)
525 | {
526 | pageFooterFont=font;
527 | }
528 |
529 | void PageFooter::resetPageNumber()
530 | {
531 | pageNumber=1;
532 | }
533 |
534 | void PageFooter::startDrawFooter()
535 | {
536 | //保存当前字体
537 | QFont font=mpainter->font();
538 | //设置页脚字体
539 | mpainter->setFont(pageFooterFont);
540 | //绘制制表人
541 | if(mzbr){
542 | mpainter->translate(-mpainter->transform().dx()+40, -mpainter->transform().dy()+mpainter->viewport().height() - 20);
543 | mpainter->drawText(0, 0, QString("制表人: %1").arg(creater));
544 | }
545 | //绘制页码
546 | if(mym){
547 | mpainter->translate(-mpainter->transform().dx()+mpainter->viewport().width()/2-15, -mpainter->transform().dy()+mpainter->viewport().height() - 20);
548 | mpainter->drawText(0, 0, QString("第 %1 页").arg(pageNumber));
549 | pageNumber += 1;
550 | }
551 | //绘制制表日期
552 | if(mzbsj){
553 | mpainter->translate(-mpainter->transform().dx()+mpainter->viewport().width()-170, -mpainter->transform().dy()+mpainter->viewport().height() - 20);
554 | mpainter->drawText(0, 0, QString("制表日期: %1").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd")));
555 | }
556 | //恢复之前字体
557 | mpainter->setFont(font);
558 | }
559 |
560 | void PageFooter::setCreater(const QString &name)
561 | {
562 | creater=name;
563 | }
564 |
565 | //--------页脚类结束-------------
566 |
567 | //--------标题类-------------
568 | PageTitle::PageTitle(QPainter *painter, QPrinter* printer)
569 | {
570 | mpainter=painter;
571 | mprinter = printer;
572 | QFont font = QFont("宋体",20);
573 | QFont sidefont = QFont("宋体",9);
574 | font.setBold(true);
575 | titleFont=font;
576 | sidetitleFont = sidefont;
577 | }
578 |
579 | void PageTitle::setTitleFont(QFont font)
580 | {
581 | titleFont=font;
582 | }
583 |
584 | void PageTitle::setSideTitleFont(QFont font)
585 | {
586 | sidetitleFont=font;
587 | }
588 |
589 | void PageTitle::setPageTitle(const QString &title)
590 | {
591 | mtitle=title;
592 | }
593 |
594 | void PageTitle::setSideTitle(const QStringList &sidetitle)
595 | {
596 | msideTitles = sidetitle;
597 | }
598 |
599 | void PageTitle::startDrawTitle()
600 | {
601 | //回到原点
602 | mpainter->translate(-mpainter->transform().dx(),-mpainter->transform().dy());
603 | //设置字体
604 | QFont font=mpainter->font();
605 | mpainter->setFont(titleFont);
606 | //获取标题宽度
607 | QPainter testSize;
608 | QImage* image = new QImage(10, 10, QImage::Format_RGB32);
609 | image->setDotsPerMeterX(mprinter->logicalDpiX() * 100 / 2.54); // 2.54 cm = 1 inch
610 | image->setDotsPerMeterY(mprinter->logicalDpiY() * 100 / 2.54);
611 | testSize.begin(image);
612 | testSize.setFont(titleFont);
613 | QRect rect(0, 0, 1000, 1000);
614 | QRect realRect;
615 | testSize.drawText(rect, Qt::AlignmentFlag::AlignCenter | Qt::TextFlag::TextSingleLine, mtitle, &realRect);
616 | int left= (mpainter->viewport().width()-realRect.width())*0.5;
617 | //绘制标题
618 | mpainter->drawText(left,QTableViewPrinter::headerHeight/2+realRect.height()/2,mtitle);
619 | //绘制副标题(均布绘制在表格上方, 标题下方)
620 | if(msideTitles.size()>0){
621 | mpainter->setFont(sidetitleFont);
622 | testSize.setFont(sidetitleFont);
623 | QList widthList;
624 | int totalwidth=0;
625 | int height =0;
626 | for(int i=0;i1)
635 | midWidth=(mpainter->viewport().width()-(QTableViewPrinter::leftBlank+QTableViewPrinter::rightBlank+totalwidth))/(msideTitles.size()-1);
636 | for(int i=0;idrawText(QTableViewPrinter::leftBlank+tempWidth,QTableViewPrinter::headerHeight-height/2,msideTitles.at(i));
642 | }
643 | }
644 | mpainter->setFont(font);
645 | }
646 | //--------标题类结束-------------
647 |
--------------------------------------------------------------------------------
/QTableViewPrinter/qtableviewprinter.h:
--------------------------------------------------------------------------------
1 | #ifndef QTABLEVIEWPRINTER_H
2 | #define QTABLEVIEWPRINTER_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | class QPainter;
10 | class QAbstractItemModel;
11 |
12 | enum TitleFlag{
13 | FIRST_PAGE=0X1,
14 | EVERY_PAGE=0X2,
15 | };
16 |
17 | struct PrintColumn{
18 | QString name;
19 | int modelColumn;
20 | int columnWidth;
21 | };
22 |
23 | struct mergeColumn{
24 | QString text;
25 | QStringList columnList;
26 | };
27 |
28 | typedef QList PrintColumnList;
29 | typedef QHash> MergeColumnHash;
30 |
31 |
32 | //标题
33 | class PageTitle
34 | {
35 | public:
36 | PageTitle(QPainter *painter, QPrinter* printer);
37 | virtual ~PageTitle(){}
38 | void setPageTitle(const QString& title);
39 | void setTitleFont(QFont font);
40 | void setSideTitleFont(QFont font);
41 | void setSideTitle(const QStringList& sidetitle);
42 | public:
43 | virtual void startDrawTitle();
44 | private:
45 | QPainter* mpainter;
46 | QPrinter* mprinter;
47 | QFont titleFont;
48 | QFont sidetitleFont;
49 | QString mtitle;
50 | QStringList msideTitles;
51 | };
52 |
53 | //页眉
54 | class PageHeader
55 | {
56 | public:
57 | PageHeader(QPainter *painter);
58 | virtual ~PageHeader(){}
59 | void setPageHeaderFont(QFont font);
60 | public:
61 | virtual void startDrawHeader();
62 | private:
63 | QPainter* mpainter;
64 | QFont pageHeaderFont;
65 | };
66 |
67 | //页脚
68 | class PageFooter
69 | {
70 | public:
71 | PageFooter(QPainter *painter);
72 | ~PageFooter(){}
73 | virtual void startDrawFooter();
74 | void setCreater(const QString& name);
75 | void setPageFooterFont(QFont font);
76 | void resetPageNumber();
77 | void setViewFlag(bool zbr=true, bool ym=true, bool zbsj=true);
78 | private:
79 | QPainter* mpainter;
80 | static int pageNumber;
81 | QString creater;
82 | QFont pageFooterFont;
83 | bool mzbr,mym, mzbsj;
84 | };
85 |
86 | //主体内容
87 | class QTableViewPrinter
88 | {
89 | public:
90 | QTableViewPrinter(QPainter *painter, QPrinter *printer);
91 | bool printTable(QTableView* tableView, const QStringList &totalFields, const QStringList &visualFields);
92 | QString lastError();
93 | static int headerHeight;
94 | static int leftBlank;
95 | static int rightBlank;
96 |
97 | //设置单元格内间距
98 | void setCellMargin(int left = 10, int right = 5, int top = 5, int bottom = 5);
99 | //设置表格外边距
100 | void setPageMargin(int left = 50, int right = 20, int top = 20, int bottom = 20);
101 | //设置页面绘制画笔
102 | void setPen(QPen pen);
103 | //设置表格头字体
104 | void setHeadersFont(QFont font);
105 | //设置表格内容字体
106 | void setContentFont(QFont font);
107 | //设置表格头字体颜色
108 | void setHeaderColor(QColor color);
109 | //设置表格内容颜色
110 | void setContentColor(QColor color);
111 | //设置文本填充方式(超出部分换行或者不换行)
112 | void setTextWordWrap(Qt::TextFlag Wrap);
113 | //设置最大行高
114 | void setMaxRowHeight(int height);
115 | //设置文本对齐方式
116 | void setTextAlign(Qt::AlignmentFlag align);
117 | //设置标题显示方式(只在第一页显示或者每一页都显示标题)
118 | void setTitleFlag(const TitleFlag type);
119 | //设置表格头显示方式(只在第一页显示或者每一页都显示)
120 | void setHeaderFlag(bool flag);
121 |
122 | //获取标题实例
123 | void setPagerTitle(PageTitle *pagetitle);
124 | //获取页眉实例
125 | void setPageHeader(PageHeader *pageheader);
126 | //获取页脚实例
127 | void setPagerFooter(PageFooter *pagefooter);
128 | private:
129 | QPainter *painter;
130 | QPrinter *printer;
131 | PageTitle *pageTitle;
132 | PageHeader *pageHeader;
133 | PageFooter *pageFooter;
134 | QTableView *mTableView;
135 | QAbstractItemModel *model;
136 |
137 | int topMargin;
138 | int bottomMargin;
139 | int leftMargin;
140 | int rightMargin;
141 | int bottomHeight;
142 | int maxRowHeight;
143 | int mheaderRowHeight;
144 |
145 | QPen pen;
146 | QFont headersFont;
147 | QFont contentFont;
148 | QColor headerColor;
149 | QColor contentColor;
150 | QStringList mHeaderTitles;
151 | Qt::TextFlag textLineFlag;
152 | Qt::AlignmentFlag textAlign;
153 | TitleFlag titleFlag;
154 | PrintColumnList mColumnList;
155 | MergeColumnHash _mergeColumnHash;
156 | bool mheaderFlag;
157 | QString error;
158 |
159 | private:
160 | //获取画笔当前位置(测试用)
161 | void position(const QString& str);
162 | //解析表格头数据(区分隐藏列,需要合并的列以及计算列宽)
163 | bool setPrintColumnList(const QStringList &list);
164 | //主体绘制方法
165 | bool paintTable(int row=0, int column=0, bool headFlag=false);
166 | };
167 | #endif // QTABLEVIEWPRINTER_H
168 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # QTableViewPrinter
2 | 用于Qt qtableview的打印, 功能相对完善 功能有借鉴此处: https://github.com/T0ny0/Qt-Table-Printer.git, 感谢
3 |
4 | 一.开发环境
5 | ---
6 | * win10-64bit;
7 | * QT5.6.1-MINGW;
8 |
9 | 二.功能特点
10 | ---
11 | * 支持页眉, 页脚.
12 | * 支持标题,副标题
13 | * 支持多层表头, 表头合并
14 | * 打印宽度与qtableview列宽成比例, 调整qtableview即可调整打印宽度
15 | * 超出宽度的列自动换页, 超出高度的行自动换页
16 | * 支持打印可选字段, 选择什么字段需要自己来实现了, 没有设置隐藏字段不打印, 因为当前项目需要, 打印字段由客户自己选
17 |
18 | 三.示例截图
19 | ---
20 | * 初始qtableview界面.
21 | 
22 | * 预览效果
23 | 
24 | * 调整列宽
25 | 
26 | * 再次预览, 因超出当前页最大列宽, 自动换页
27 | 
28 | 
29 |
30 | 四.LICENSE
31 | ---
32 | [BSD License](./LICENSE)
33 |
34 | 五.如有疑问, CONTACT ME
35 | ---
36 | wechat: `tonyonce`
37 |
--------------------------------------------------------------------------------
/images/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonyonce2017/QTableViewPrinter/a08ae4b92f10f92365b78f8f6af593c6ec1e44b0/images/1.png
--------------------------------------------------------------------------------
/images/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonyonce2017/QTableViewPrinter/a08ae4b92f10f92365b78f8f6af593c6ec1e44b0/images/2.png
--------------------------------------------------------------------------------
/images/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonyonce2017/QTableViewPrinter/a08ae4b92f10f92365b78f8f6af593c6ec1e44b0/images/3.png
--------------------------------------------------------------------------------
/images/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonyonce2017/QTableViewPrinter/a08ae4b92f10f92365b78f8f6af593c6ec1e44b0/images/4.png
--------------------------------------------------------------------------------
/images/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tonyonce2017/QTableViewPrinter/a08ae4b92f10f92365b78f8f6af593c6ec1e44b0/images/5.png
--------------------------------------------------------------------------------