一、前言
在桌面软件开发中,经常会遇到报告、单据、检测报表类界面渲染需求。很多学者第一反应是用 QWidget 堆控件、QTableWidget 做表格,但在做高定制化科技风、工业风报告的时候,控件的边框、渐变背景、霓虹灯质感、自定义表头样式会非常难调,控件组合很容易出现排版错位、样式不统一的问题。
这时候,QPainter直接绘图就成了最优解。现在有了AI的加持,我们可以摆脱控件布局的限制,可以自由实现赛博科技感、深色霓虹边框、渐变文字等 UI 效果。
本文基于 C++ + Qt,使用 QPainter 完整复刻一份肿瘤标志物检测报告界面,实现标题栏、个人信息区、带分割线的检测表格、底部提示栏全套效果。可以给大家提供领高,同时如果有适配性项目也可以直接迁移到医疗检测系统、工业检测软件的报告打印 / 预览模块。
重要说明:本界面仅为 UI 技术演示,不代表真实医疗报告,医疗报告需要遵循医疗机构规范。
二、作品展示
先来上作品



最终实现效果如上图:深色科技网格背景,青蓝色霓虹发光边框,大标题 + 英文副标题;
-
顶部区域:姓名、年龄、检测日期、报告编号、实验室信息文本排版;
-
中间核心模块:带圆角外框的 "检测数据" 模块,内部绘制完整表格,包含项目、缩写、结果、参考范围、单位、评估六列表格;
-
表格内填充肿瘤标志物检测项目(CEA、AFP、CA125、CA199、β2‑MG、HE4)以及对应参考范围与单位;
-
底部提示栏:圆角提示框,输出免责重要提示文本; 整体配色深色底色 + 青蓝科技色调,模拟数字检验中心的数字化报告风格,AI背景图层+ QPainter 绘制,不使用 QTableWidget 等控件。
项目创意点:
1、放弃传统控件,QPainter+AI背景实现报表
传统做法用 QTableWidget,很难实现圆角发光外框、渐变边框效果。
2、科技深色 UI 配色体系整体采用深色底色,搭配青蓝色科技主题色,区分标题文字、表头背景、表格行背景、提示栏背景。表头使用渐变填充,表格奇偶行可以扩展做颜色区分,非常适合医疗、工业检测类软件风格。
3、表格通用绘制逻辑,可复用
封装表格绘制函数,传入表头数组、数据数组、单元格宽高,即可自动绘制网格、填充文字。
4、文本多区域分区排版
页面划分为:标题区、个人信息区、表格组件区、底部提示区。不同区域坐标隔离,后续修改某一块内容,不会干扰其他区域,方便迭代。
三、实现流程
1、主窗口MainWindow
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
timer = new QTimer(); // 创建定时器对象
connect(timer,SIGNAL(timeout()),this,SLOT(SlotTimer()));
}
2、核心代码
主要在CustomWidget.cpp中
//绘制文本
void DrawText(QPainter &painter,const QRectF &rect,QString str,double angle,int size,QString fontFamily,int textAlignment)
{
QRectF rotatedRect(-rect.width()/2, -rect.height()/2, rect.width(), rect.height());
qreal cx = rect.x() + rect.width() / 2;
qreal cy = rect.y() + rect.height() / 2;
QFont font = QFont(fontFamily, size);
painter.setFont(font);
painter.save();
painter.translate(cx, cy);
painter.scale(1, -1);
painter.rotate(-angle);
painter.drawText(rotatedRect,textAlignment,str);
painter.restore();
}
//绘制图片
void DrawImage(QPainter &painter, QImage &image, const QRectF &rect,double angle)
{
QRectF rotatedRect(-rect.width()/2, -rect.height()/2, rect.width(), rect.height());
qreal cx = rect.x() + rect.width() / 2;
qreal cy = rect.y() + rect.height() / 2;
painter.save();
painter.translate(cx, cy);
painter.rotate(angle);
painter.drawImage(rotatedRect, image);
painter.restore();
}
//绘制矩形
void rotateAndPaintRect(QPainter *painter, const QRectF &rect, int angle,bool isRound = false,int rx = 0,int ry = 0)
{
qreal cx = 0;
qreal cy = 0;
cx = rect.center().x();
cy = rect.center().y();
painter->save();
painter->translate(cx ,cy);
painter->rotate(angle);
QPointF drawOffset = rect.topLeft() - QPointF(cx,cy);
painter->drawRect(drawOffset.x(), drawOffset.y(), rect.width(), rect.height());
painter->restore();
}
四、源码开放
本期源码开放,有需要的朋友可以去下面位置找我~