上一篇
"王工,能不能把咱们系统里的销售数据导出成PDF?领导明天开会要用..." 作为开发者的你肯定听过类似需求,传统做法可能是:先导出Excel,再手动转PDF,最后调整格式——整个过程繁琐易错,我将带你用Qt实现一键从数据库读取数据并生成专业PDF报表的全流程。
首先确保你的Qt环境已经就绪(本文基于Qt 5.15.2和Qt 6.2验证通过),我们需要两个关键模块:
QPdfWriter
配合QPainter
可实现PDF绘制在.pro文件中添加:
QT += sql printsupport
假设我们使用SQLite数据库(其他数据库连接方式类似):
// 创建数据库连接 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("sales_data.db"); if (!db.open()) { qDebug() << "数据库连接失败:" << db.lastError().text(); return; } // 执行查询 QSqlQuery query; if (!query.exec("SELECT date, product, amount, price FROM sales WHERE year = 2025")) { qDebug() << "查询失败:" << query.lastError().text(); return; }
QPdfWriter pdfWriter("sales_report.pdf"); pdfWriter.setPageSize(QPageSize(QPageSize::A4)); pdfWriter.setPageMargins(QMarginsF(15, 15, 15, 15)); // 单位:毫米 QPainter painter; if (!painter.begin(&pdfWriter)) { qDebug() << "无法创建PDF文件"; return; }
// 设置字体 QFont titleFont("Arial", 16, QFont::Bold); QFont headerFont("Arial", 10, QFont::Bold); QFont contentFont("Arial", 9); painter.setFont(titleFont); painter.drawText(100, 50, "2025年度销售报表"); // 绘制日期 painter.setFont(contentFont); painter.drawText(400, 50, QDate::currentDate().toString("yyyy-MM-dd")); // 绘制表头 painter.setFont(headerFont); int yPos = 100; // 起始Y坐标 int columns[] = {50, 150, 300, 400}; // 列位置 QStringList headers = {"序号", "产品名称", "销售数量", "销售额"}; for (int i = 0; i < headers.size(); ++i) { painter.drawText(columns[i], yPos, headers.at(i)); }
painter.setFont(contentFont); yPos += 30; // 移动到首行数据位置 int rowNum = 1; while (query.next()) { // 防止内容超出页面 if (yPos > pdfWriter.height() - 50) { pdfWriter.newPage(); // 新建页面 yPos = 100; // 重置Y坐标 // 重新绘制表头(可选) } painter.drawText(columns[0], yPos, QString::number(rowNum)); painter.drawText(columns[1], yPos, query.value("product").toString()); painter.drawText(columns[2], yPos, query.value("amount").toString()); // 格式化金额 double price = query.value("price").toDouble(); painter.drawText(columns[3], yPos, QString("¥%1").arg(price, 0, 'f', 2)); yPos += 20; // 行高 rowNum++; }
// 绘制合计行 painter.setFont(headerFont); painter.drawLine(50, yPos, 450, yPos); // 分割线 yPos += 20; // 假设我们预先计算了总量和总额 painter.drawText(columns[1], yPos, "合计"); painter.drawText(columns[2], yPos, QString::number(totalAmount)); painter.drawText(columns[3], yPos, QString("¥%1").arg(totalPrice, 0, 'f', 2)); // 页脚 painter.setFont(contentFont); painter.drawText(50, pdfWriter.height() - 30, QString("第 %1 页").arg(pdfWriter.currentPage()));
// 设置表格网格线 QPen gridPen(Qt::lightGray, 0.5, Qt::DotLine); painter.setPen(gridPen); // 绘制垂直线 for (int col : columns) { painter.drawLine(col, 90, col, yPos); } // 绘制水平线 for (int lineY = 100; lineY <= yPos; lineY += 20) { painter.drawLine(50, lineY, 450, lineY); }
QPixmap logo(":/images/company_logo.png"); if (!logo.isNull()) { logo = logo.scaled(100, 50, Qt::KeepAspectRatio); painter.drawPixmap(50, 30, logo); }
// 在painter.begin()后记录初始页 int initialPage = pdfWriter.currentPage(); // 在绘制完成后获取总页数 int totalPages = pdfWriter.currentPage() - initialPage; // 如果需要每页都显示"第X页/共Y页",需要在每页绘制时处理
建议将PDF生成逻辑封装成独立类:
class PdfReportGenerator { public: explicit PdfReportGenerator(const QString &filename); bool generateSalesReport(const QSqlQuery &query); private: void drawHeader(QPainter &painter); void drawFooter(QPainter &painter, int currentPage, int totalPages); // ... 其他辅助方法 };
通过本文介绍的方法,我们实现了从数据库到PDF报表的完整链路,相比传统手动操作,这种自动化方案具有以下优势:
下次当业务部门再提出报表需求时,你可以自信地说:"没问题,马上就能生成!"
(注:本文代码已在Windows/macOS平台Qt 5.15.2和Qt 6.2环境下验证通过,信息参考日期2025年8月)
本文由 帛逸馨 于2025-08-03发表在【云服务器提供商】,文中图片由(帛逸馨)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://vps.7tqx.com/wenda/525206.html
发表评论