├── 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 | ![image](./images/1.png) 22 | * 预览效果
23 | ![image](./images/2.png) 24 | * 调整列宽
25 | ![image](./images/3.png) 26 | * 再次预览, 因超出当前页最大列宽, 自动换页 27 | ![image](./images/4.png) 28 | ![image](./images/5.png) 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 --------------------------------------------------------------------------------