21、Qt绘图与图形视图:QPainter基础、绘制基本图形、QPen与QBrush、QGraphicsView框架

说到Qt绘图,我脑子里第一个蹦出来的就是QPainter。这玩意儿说白了就是Qt的画笔,你想在屏幕上画什么,都得靠它。我记得刚接触Qt那会儿,总觉得绘图是件很神秘的事,后来才发现,其实就跟小时候在纸上画画差不多——你拿笔,选颜色,然后开始画。

QPainter基础:你的第一支画笔

QPainter是Qt绘图的核心类。它可以在任何QPainterDevice上绘制,比如QWidget、QPixmap、QImage等。使用起来也很简单,三步走:

  1. 创建QPainter对象
  2. 调用绘制函数
  3. 销毁QPainter对象(或调用end())

我习惯在paintEvent里使用QPainter,因为这是Qt推荐的绘制时机。你想想看,如果随便找个地方就开始画,那窗口一刷新,画的东西就没了。

void MyWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing); // 抗锯齿,让线条更平滑
    painter.drawLine(10, 10, 100, 100);
    painter.drawRect(50, 50, 200, 100);
    painter.drawEllipse(100, 100, 80, 80);
}
小提示:记得在paintEvent里创建QPainter,不要在其他地方创建后传进来用。我曾经踩过这个坑,画出来的东西时有时无,排查了半天才发现是绘制时机不对。

绘制基本图形:从点线面开始

Qt提供了丰富的图形绘制函数。我整理了一下常用的,你一看就明白:

函数 作用 参数说明
drawPoint(x, y) 画点 坐标位置
drawLine(x1, y1, x2, y2) 画线 起点和终点坐标
drawRect(x, y, w, h) 画矩形 左上角坐标、宽高
drawEllipse(x, y, w, h) 画椭圆/圆 外接矩形参数
drawArc(x, y, w, h, startAngle, spanAngle) 画弧线 角度用1/16度为单位
drawPie(x, y, w, h, startAngle, spanAngle) 画扇形 和drawArc类似,但会闭合到圆心
drawText(x, y, text) 画文字 坐标和文本内容

嗯,这里要注意:drawArc和drawPie的角度单位是1/16度。也就是说,如果你要画一个90度的弧,startAngle和spanAngle都得乘以16。我第一次用的时候直接传了90,结果画出来一个奇怪的东西……

// 画一个从0度到90度的弧
painter.drawArc(10, 10, 100, 100, 0, 90 * 16);

QPen与QBrush:线条和填充的灵魂

QPen控制线条的样式,QBrush控制填充的样式。这两个类配合使用,能画出各种效果。

QPen常用设置:

  • 颜色:setColor(QColor)
  • 宽度:setWidth(int)
  • 样式:setStyle(Qt::PenStyle),比如实线、虚线、点线
  • 端点样式:setCapStyle(Qt::PenCapStyle),圆头、方头等
  • 连接样式:setJoinStyle(Qt::PenJoinStyle),圆角连接、斜角连接等

QBrush常用设置:

  • 颜色:setColor(QColor)
  • 样式:setStyle(Qt::BrushStyle),比如纯色、渐变、纹理
  • 渐变:可以使用QLinearGradient、QRadialGradient、QConicalGradient
重点:QPen和QBrush的设置顺序很重要。我建议先设置QPen,再设置QBrush,这样代码逻辑清晰,不容易搞混。
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);

// 设置画笔:红色,宽度3,虚线
QPen pen(Qt::red, 3, Qt::DashLine);
painter.setPen(pen);

// 设置画刷:蓝色,纯色填充
QBrush brush(Qt::blue, Qt::SolidPattern);
painter.setBrush(brush);

painter.drawRect(50, 50, 200, 100);

这段代码画出来的是一个红色虚线边框、蓝色填充的矩形。你想想看,如果不设置画刷,默认就是白色填充,那效果就差远了。

QGraphicsView框架:当绘图变得复杂

如果你只是画几个简单的图形,QPainter完全够用。但一旦涉及到大量图形、交互操作(拖拽、缩放、旋转),QPainter就力不从心了。这时候就该QGraphicsView框架登场了。

QGraphicsView框架由三部分组成:

  • QGraphicsScene:场景,管理所有图形项
  • QGraphicsItem:图形项,你要画的每个图形都是一个Item
  • QGraphicsView:视图,负责显示场景

我个人的习惯是:先创建场景,再往场景里添加Item,最后用View来显示。这种模式有点像MVC,场景是模型,视图是展示层。

// 创建场景
QGraphicsScene *scene = new QGraphicsScene(this);
scene->setSceneRect(0, 0, 400, 300);

// 添加矩形项
QGraphicsRectItem *rectItem = new QGraphicsRectItem(50, 50, 100, 80);
rectItem->setBrush(QBrush(Qt::green));
rectItem->setPen(QPen(Qt::black, 2));
scene->addItem(rectItem);

// 添加椭圆项
QGraphicsEllipseItem *ellipseItem = new QGraphicsEllipseItem(200, 50, 80, 80);
ellipseItem->setBrush(QBrush(Qt::yellow));
scene->addItem(ellipseItem);

// 创建视图并显示
QGraphicsView *view = new QGraphicsView(scene, this);
view->setRenderHint(QPainter::Antialiasing);
view->show();
避坑指南:我曾经在项目中直接用QPainter画了几百个图形,结果界面卡得不行。后来换成QGraphicsView框架,性能直接起飞。所以,如果你要画的东西超过20个,或者需要交互,果断用QGraphicsView。

知识体系总览

下面这张图是我整理的本章知识体系,你看一眼就能明白各个知识点之间的关系:

Qt绘图与图形视图知识体系 Qt绘图体系 QPainter基础 QPen与QBrush QGraphicsView框架 paintEvent中创建 绘制基本图形 抗锯齿设置 QPen:线条样式 QBrush:填充样式 颜色、宽度、样式 纯色、渐变、纹理 QGraphicsScene:场景 QGraphicsItem:图形项 QGraphicsView:视图

从这张图你可以看到,Qt绘图体系分为三大块。左边是QPainter基础,适合简单绘制;中间是QPen和QBrush,控制样式;右边是QGraphicsView框架,适合复杂场景。我个人建议你从左边开始学,逐步过渡到右边。

实战经验分享

我在做一个地图编辑器项目时,需要绘制大量自定义图形。一开始我用QPainter在QWidget上直接画,结果每次刷新都要重绘所有图形,性能很差。后来改用QGraphicsView框架,每个图形作为一个Item,只有被修改的Item才会重绘,性能提升了好几个数量级。

另外,QPen和QBrush的配合使用也很讲究。比如你要画一个带渐变填充的圆,可以这样:

QRadialGradient gradient(50, 50, 50, 50, 50);
gradient.setColorAt(0, Qt::white);
gradient.setColorAt(1, Qt::blue);

QBrush brush(gradient);
painter.setBrush(brush);
painter.drawEllipse(10, 10, 80, 80);

这段代码画出来的是一个从中心白色渐变到边缘蓝色的圆。你想想看,如果只用纯色填充,效果就差远了。

小技巧:调试绘图代码时,可以先用QPen把边框画出来,确认位置正确后再加填充。这样能快速定位问题。

好了,关于Qt绘图与图形视图,我就讲这么多。记住,QPainter是基础,QPen和QBrush是灵魂,QGraphicsView是进阶。从简单到复杂,一步步来,你也能画出漂亮的界面。


公众号:蓝海资料掘金营,微信deep3321