绘图
Qt 提供了画图相关的 API,可以允许我们在窗口上绘制任意的图形形状,来完成更复杂的界面设计。
绘图API核心类
类 | 说明 |
---|---|
QPainter | "画家" 用来绘图的对象,提供了一系列 drawXXX 方法,可以允许我们绘制各种图形 |
QPaintDevice | "画板" 描述了 QPainter 把图形画到哪个对象上,之前的 QWidget 也是一种 QPaintDevice |
QPen | "画笔" 描述了 QPainter 画出来的线是什么样的 |
QBrush | "画刷" 描述了 QPainter 填充了一个区域是什么样的 |
QPainter
这里画笔的样式有以下几种:
QBrush
![](https://i-blog.csdnimg.cn/direct/b10d1213042f4f5791369287aa5922b5.png)
其中画刷的样式有以下几种:
例如使用 Qt::DiagCrossPattern
![](https://i-blog.csdnimg.cn/direct/6ed7825fe6f14f6f88e8f438e4685a3e.png)
绘制图片
![](https://i-blog.csdnimg.cn/direct/a9f6217b79db476594da042c88077225.png)
平移坐标轴:translate(x, y) 表示水平方向上平移 x 单位,垂直方向上平移 y 单位。窗口默认大小为800*600,所以 translate(800,600) 后,坐标原点就跑右下角了。
旋转坐标轴:rotate(angel) 表示将坐标原点旋转 angel 角度,单位是度。angel 为正数表示顺时针。
![](https://i-blog.csdnimg.cn/direct/9f18044057bb4cff8ba681945fdc737e.png)
视口和窗口
视口是指绘图设备的任意一个矩形区域,它使用物理坐标系。我们可以只选取物理坐标系中的一个矩形区域来绘图,默认情况下,视口等于绘图设备的整个矩形区域。窗口与视口是同一个矩形区域,但是窗口是用逻辑坐标系定义的,窗口可以直接定义矩形区域的逻辑坐标范围。
如下图矩形区域就是代表绘图设备的物理大小和坐标范围,假设大小为300*200像素。取其中间的一个正方形区域作为视口,卡其色的正方形区域就是视口。在绘图设备的物理坐标系中,视口的左上角坐标为 (50,0), 右下角坐标为 (250,200)。
QPainter 的函数 setViewport() 用于定义视口,有两种参数形式,其函数原型定义如下:
void QPainter::setViewport(const QRect &rectangle)
void QPainter::setViewport(int x, int y, int width, int height)
其中,(x, y) 是视口左上角在物理坐标系中的坐标,width 是视口宽度, height 是视口高度。上图中的视口需使用下面的语句:
painter.setViewport(50, 0, 200, 200);
这表示从绘图设备的物理坐标系中的一个点(50, 0) 开始,取宽度 300,高度 200像素的一个区域作为视口。对于上图视口所表示的正方形区域,我们定义如上图所示的一个窗口,窗口坐标系的原点在正方形的中心,并设置正方形的逻辑边长为 100。QPainter 的函数 setWindow() 用于定义窗口,有两种参数形式,其函数原型如下:
void QPainter::setWindow(const QRect &rectangle)
void QPainter::setWindow(int x, int y, int width, int height)
其中,(x, y) 是窗口左上角的坐标,width 是窗口逻辑宽度, height 是窗口逻辑高度。上图中的窗口需使用下面的语句:
painter.setWindow(-50, -50, 100, 100);
这表示对应于视口的正方形区域,其窗口左上角的逻辑坐标是 (-50, -50),窗口宽度为 100,高度为 100.这里设置的窗口仍为一个正方形,使得从视口变换到窗口时,长和宽的比例是相同的。实际可以任意指定窗口的逻辑坐标范围,长和宽的比例不同也是可以的。
视口窗口使用实例
使用窗口坐标系的优点是:在绘图时只需按照窗口坐标系定义来绘图,而不用关注实际的物理坐标范围。例如在一个固定边长为 100 的正方形窗口内绘图,当实际绘图设备大小变化时,绘图的图形会自动相应改变大小。这样,绘图功能与绘图设备是分离的,绘图功能可适用于不同大小、不同类型的绘图设备。
![](https://i-blog.csdnimg.cn/direct/f2f7d79af791446087809c2b097c23d3.png)
取高度和宽度中较小的一边为正方形边长,且图形是自动缩放的。
代码如下:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
int W = width();
int H = height();
int side = qMin(W,H);
QRect rect((W-side)/2,(H-side)/2,side,side);
painter.drawRect(rect);
painter.setViewport(rect);
painter.setWindow(-100,-100,200,200);
QPen pen;
pen.setWidth(1);
pen.setColor(Qt::red);
pen.setStyle(Qt::SolidLine);
pen.setCapStyle(Qt::FlatCap);
pen.setJoinStyle(Qt::BevelJoin);
painter.setPen(pen);
for(int i = 0; i < 36; i++)
{
painter.drawEllipse(QPoint(50,0),50,50);
painter.rotate(10);//画一个圆旋转10度
}
}
增加渐变填充和叠加效果的设置:
![](https://i-blog.csdnimg.cn/direct/005ce0dee60c4fd0bde0cce0ba57675c.png)
代码如下:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
int W = width();
int H = height();
int side = qMin(W,H);
QRect rect((W-side)/2,(H-side)/2,side,side);
painter.drawRect(rect);
painter.setViewport(rect);
painter.setWindow(-100,-100,200,200);
QPen pen;
pen.setWidth(1);
pen.setColor(Qt::red);
pen.setStyle(Qt::SolidLine);
pen.setCapStyle(Qt::FlatCap);
pen.setJoinStyle(Qt::BevelJoin);
painter.setPen(pen);
//线性渐变
QLinearGradient linearGrad(0,0,100,0);//从左到右
linearGrad.setColorAt(0,Qt::yellow);//起点颜色
linearGrad.setColorAt(1,Qt::green);//终点颜色
linearGrad.setSpread(QGradient::PadSpread);//展布模式
painter.setBrush(linearGrad);
//设置组合模式
painter.setCompositionMode(QPainter::CompositionMode_Difference);
// painter.setCompositionMode(QPainter::RasterOp_NotSourceXorDestination);
// painter.setCompositionMode(QPainter::CompositionMode_Exclusion);
for(int i = 0; i < 36; i++)
{
painter.drawEllipse(QPoint(50,0),50,50);
painter.rotate(10);//画一个圆旋转10度
}
}
以上窗口视口内容及代码为王维波等老师的书籍 《Qt6 C++ 开发指南》中的内容。