21、Qt绘图与图形视图:QPainter基础、绘制基本图形、QPen与QBrush、QGraphicsView框架
说到Qt绘图,我脑子里第一个蹦出来的就是QPainter。这玩意儿说白了就是Qt的画笔,你想在屏幕上画什么,都得靠它。我记得刚接触Qt那会儿,总觉得绘图是件很神秘的事,后来才发现,其实就跟小时候在纸上画画差不多——你拿笔,选颜色,然后开始画。
QPainter基础:你的第一支画笔
QPainter是Qt绘图的核心类。它可以在任何QPainterDevice上绘制,比如QWidget、QPixmap、QImage等。使用起来也很简单,三步走:
- 创建QPainter对象
- 调用绘制函数
- 销毁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);
}
绘制基本图形:从点线面开始
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
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();
知识体系总览
下面这张图是我整理的本章知识体系,你看一眼就能明白各个知识点之间的关系:
从这张图你可以看到,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);
这段代码画出来的是一个从中心白色渐变到边缘蓝色的圆。你想想看,如果只用纯色填充,效果就差远了。
好了,关于Qt绘图与图形视图,我就讲这么多。记住,QPainter是基础,QPen和QBrush是灵魂,QGraphicsView是进阶。从简单到复杂,一步步来,你也能画出漂亮的界面。
公众号:蓝海资料掘金营,微信deep3321