news 2026/4/21 19:53:16

Qt5/6实战:用QPainter在Widget上画个带边框和填充色的矩形(附源码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt5/6实战:用QPainter在Widget上画个带边框和填充色的矩形(附源码)

Qt5/6实战:用QPainter绘制带边框与填充色的矩形

第一次在Qt中看到QPainter绘制出的矩形时,那种"代码即界面"的奇妙感至今难忘。作为Qt图形系统的核心组件,QPainter就像数字世界的画笔,让开发者能够精确控制每个像素的呈现。本文将带你从零开始,在Widget上绘制一个具有自定义边框和填充效果的矩形,过程中不仅会涉及基础API调用,更会分享那些官方文档没明说但实际开发中绕不开的细节。

1. 环境准备与项目创建

推荐使用Qt Creator作为开发环境,无论是Qt5.15还是Qt6.2都能完美运行本示例。新建项目时选择"Qt Widgets Application",模板会自动生成主窗口类。这里有个容易踩坑的地方:项目命名时避免使用特殊字符和空格,否则可能遇到编译问题。

widget.h中声明重绘事件处理函数:

protected: void paintEvent(QPaintEvent *event) override;

提示:现代Qt开发中建议使用override关键字明确表示重写虚函数,这能让编译器帮助检查函数签名是否正确。

2. 理解Qt坐标系系统

在实现绘制逻辑前,必须清楚Qt的坐标系规则:

  • 原点(0,0)位于Widget的内容区域左上角(不包括窗口边框)
  • X轴向右为正方向,Y轴向下为正方向
  • 默认单位是像素,但可通过QTransform实现缩放
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); // 测试坐标系 painter.drawText(10, 20, "坐标系原点在这里"); }

运行这段代码,文字会出现在距离窗口内边框右侧10像素、下方20像素的位置。如果发现显示位置有偏差,检查是否忽略了窗口边框的宽度。

3. 实现基础矩形绘制

核心绘制流程分为三个关键步骤:

  1. 创建QPainter对象:绑定到当前Widget
  2. 配置绘制工具
    • QPen控制边框样式
    • QBrush控制填充样式
  3. 执行绘制命令:调用drawRect等绘图方法
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); // 配置红色虚线边框 QPen borderPen(QColor(255, 0, 0)); borderPen.setStyle(Qt::DashLine); borderPen.setWidth(3); // 配置半透明绿色填充 QBrush fillBrush(QColor(0, 255, 0, 150)); painter.setPen(borderPen); painter.setBrush(fillBrush); // 绘制矩形:左上角(50,50),宽200,高100 painter.drawRect(50, 50, 200, 100); }

参数说明表格:

参数类型说明常用值示例
QPen宽度int边框粗细1-5像素
QPen样式Qt::PenStyle边框线型SolidLine, DashLine, DotLine
QColor透明度intAlpha通道0(全透明)-255(不透明)
drawRect坐标int矩形位置尺寸(x,y,width,height)

4. 高级样式定制技巧

4.1 使用预设样式

Qt提供了多种预设颜色和样式,避免手动定义RGB值:

// 使用系统预设 QPen pen(Qt::GlobalColor::darkBlue); pen.setStyle(Qt::DashDotLine); // 画刷填充图案 QBrush brush; brush.setColor(Qt::yellow); brush.setStyle(Qt::Dense4Pattern);

4.2 抗锯齿优化

绘制斜线或曲线时开启抗锯齿可获得更平滑的效果:

painter.setRenderHint(QPainter::Antialiasing); painter.drawRect(100, 100, 150, 150);

4.3 动态效果实现

结合定时器可以实现动态绘图效果。在Widget类中添加:

private slots: void animateRect(); private: int m_offset = 0;

实现动画逻辑:

// 构造函数中连接定时器 QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &Widget::animateRect); timer->start(30); // 动画处理 void Widget::animateRect() { m_offset = (m_offset + 2) % 100; update(); // 触发重绘 } void Widget::paintEvent(QPaintEvent *) { QPainter painter(this); painter.drawRect(50 + m_offset, 50, 100, 100); }

5. 常见问题解决方案

问题1:绘制内容不显示

  • 检查是否漏掉了painter.begin(this)或使用了错误的PaintDevice
  • 确认Widget的autoFillBackground属性为false

问题2:性能优化建议

  • 复杂图形考虑使用QPixmap缓存绘制结果
  • 只在变化时调用update()而非连续重绘

问题3:高DPI屏幕适配

// 获取设备像素比 qreal ratio = devicePixelRatioF(); painter.scale(ratio, ratio);

完整项目源码结构:

/ProjectRoot ├── widget.h # 头文件声明 ├── widget.cpp # 绘制实现 ├── main.cpp # 应用入口 └── CMakeLists.txt # 构建配置

实际开发中,我习惯将复杂的绘制逻辑拆分成多个方法,比如drawBorder()drawContent(),这样既方便维护也利于性能优化。当需要绘制多个矩形时,可以考虑使用QGraphicsView框架替代直接Widget绘制,这在需要交互或大量图形元素的场景下性能更好。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/21 19:51:59

Janus-Pro-7B自动化运维脚本生成:应对服务器常见问题

Janus-Pro-7B自动化运维脚本生成:应对服务器常见问题 1. 引言 你有没有过这样的经历?半夜被报警电话叫醒,登录服务器一看,原来是某个日志文件把磁盘空间占满了。手忙脚乱地写脚本清理,一边担心删错文件,一…

作者头像 李华
网站建设 2026/4/21 19:51:34

合宙Air001开发板实战指南—从零构建Keil-MDK工程与GPIO控制

1. 合宙Air001开发板初体验 第一次拿到合宙Air001开发板时,我着实被它的性价比惊艳到了。这款采用TSSOP20封装的开发板搭载ARM Cortex-M0内核,内置32KB Flash和4KB RAM,集成多路USART、IIC、SPI等通信外设,还配备了5个16位定时器、…

作者头像 李华
网站建设 2026/4/21 19:50:58

毕业季论文救星!9 款 AI 工具组合拳 选题到答辩一步到位

又到了本科生集体 “渡劫” 的毕业季:选题改到怀疑人生,文献翻到眼花缭乱,格式调到手抽筋,查重率居高不下还得兼顾实习秋招。与其硬扛熬夜爆肝,不如换个思路 —— 用对 AI 工具,让论文写作效率直接开挂。下…

作者头像 李华
网站建设 2026/4/21 19:50:14

Prism方差分析结果看不懂?手把手教你解读F值、P值与方差分析表

Prism方差分析结果看不懂?手把手教你解读F值、P值与方差分析表 第一次在Prism中跑完方差分析时,盯着那张满是数字的表格,我的反应和大多数研究者一样——这些SS、df、MS究竟在说什么?更让人焦虑的是,明明实验数据差异肉…

作者头像 李华