C++ Qt学习笔记(4)绘图

        Qt中的二维绘图基本功能是使用Qpainter在绘图设备上进行绘图,绘图设备由QpainterDevice提供,QPaintDevice是一个二维空间的抽象,可以使用QPainter在其上进行绘制,它是所有可以进行绘制的对象的基类。QPainterDevice的子类主要有QWidget, QPixmap,QPicture,QImage,QPinter,QOpenGIPainterDevice,这些设备相当于为QPainter提供了一个画布。通过绘制一些基本的图形,如点,线,圆组成自己需要的图图件,形,得到的图形是不可交互的。

       Qt中的Graphics View架构,使用QGraphicsView,QGraphicsScene,QGraphicsItem类绘图,在一个场景中可以绘制,且图件是可以交互的。

1. QPainter基本绘图:

        在绘图系统中,主要通过QPainter完成具体的绘图操作,QPaintDevice是一个可以用QPainter进行绘图的抽象二维画布。QPainterEngine为QPainter提供在不同设备上进行绘图的接口,QPainterEngine类一般只在QPainter类和QPaintDevice类的内部使用,一般不需要我们去操作它。

       QPainter在一个Paint Event事件函数中进行绘图,从画布(QWidget, QPixmap, QPicture, QImage, QPinter,     QOpenGIPainterDevice )继承的类都有Paint Event事件函数。例如创建一个Widget窗口,进行绘图,则这个Widget窗口就是需要使用的绘图设备。

       绘图的区域就是Widget内部的区域,区域内的坐标系统的单位是像素,左上角为原点(0,0),向右是X轴正向,向下是Y轴正向。绘图区域的大小可以由Widget::width()以及Widget::height()得到。

QPainter绘图的属性:
1. pen属性:是一个QPen对象,用于控制线条的颜色,宽度,线型等属性

2. brush属性:是一个QBrush对象,控制区域填充特性,如颜色,填充方式,渐变特性

3. font:QFont对象,用于绘制文字时控制文字的属性,字体,大小等

1. 首先声明绘图事件处理函数:

protected:
void paintEvent(QPaintEvent* event);

2.在paintEvent()函数中编写绘制图像的代码:

void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及绘图设备
painter.setRenderHint(QPainter::Antialiasing); // 绘画普通图形启用反走样, 即开启抗锯齿
painter.setRenderHint(QPainter::TextAntialiasing); // 绘画文字反走样, 即开启抗锯齿
int width = this->width(); // 获取绘图区域的大小
int height = this->height();
QRect rect(width/4, height/4, width/2, height/2); // 中间区域矩形框
// QPainter属性 pen,brush,font
QPen pen;
pen.setWidth(3); // 设置线宽
pen.setColor(Qt::blue);
pen.setStyle(Qt::SolidLine); // 线的样式
pen.setCapStyle(Qt::FlatCap); // 线条的端点样式
pen.setJoinStyle(Qt::BevelJoin); // 连接点的样式
painter.setPen(pen); // 设置QPainter的pen属性
// brush属性
QBrush brush;
brush.setColor(Qt::green); // 填充颜色
brush.setStyle(Qt::SolidPattern); // 填充样式
painter.setBrush(brush);
// 绘图
painter.drawRect(rect);
// 绘制直线
pen.setColor(Qt::red);
pen.setCapStyle(Qt::FlatCap);
pen.setJoinStyle(Qt::BevelJoin);
painter.setPen(pen);
painter.drawLine(QPoint(5, 5), QPoint(width-10, height-10));
}

绘图结果:

关于绘制图像中的抗锯齿,可以参考博客:https://blog.csdn.net/xiezhongyuan07/article/details/97116491

同时,可以擦除矩形中填充的颜色,以及重新填充:

painter.eraseRect(rect); // 擦除矩形区域的内容
// 可以重新填充矩形区域
brush.setColor(Qt::black);
painter.fillRect(rect, brush);


QPainter的三个属性介绍:

1. QPen的属性:

Qpen主要用于在绘图时对线条进行控制,包括线宽,颜色,线型的。

QPen主要的接口函数有:

更改器:(设置属性)

1.pen.setColor(Qt::red);                        设置颜色
2.pen.setCapStyle(Qt::FlatCap);           设置端点样式
3. pen.setJoinStyle(Qt::BevelJoin);       设置连接样式

4. pen.setWidth()                                  设置宽度

5. pen.setStyle()                                   设置样式

访问器:(获取属性)

1.pen.color(Qt::red);                             获取pen的颜色
2.pen.capStyle(Qt::FlatCap);                       获取端点样式
3. pen.joinStyle(Qt::BevelJoin);           连接样式

4. pen.width()                                       宽度

5. pen.style()                                   样式

线条样式主要有六种:
1. SolidLine

2. DashLine

3. DotLine

4. DashDotLine

5. DashDotDotLine

6. CustomDashLine

7.NoPen

端点样式有三种:

1. SquareCap

2. FlatCap

3. RoundCap

连接样式也有三种:

1. BevelJoin

2. MiterJoin

3. RoundJoin

2. QBrush介绍:

QBrush定义了QPainter绘图时的填充性能,包括颜色,填充样式,填充材质。

QBrush的主要函数有以下几种:
void    setColor ( Qt::GlobalColor color )
void    setStyle ( Qt::BrushStyle style )
void    setTexture ( const QPixmap & pixmap )
void    setTextureImage ( const QImage & image )

填充样式setStyle()的参数是一个枚举类型,主要有以下几种:

例如,用几种不同的方式填充矩形区域:

void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及绘图设备
painter.setRenderHint(QPainter::Antialiasing); // 绘画普通图形启用反走样, 即开启抗锯齿
painter.setRenderHint(QPainter::TextAntialiasing); // 绘画文字反走样, 即开启抗锯齿
int width = this->width(); // 获取绘图区域的大小
int height = this->height();
QRect rect(width/4, height/4, width/2, height/2); // 中间区域矩形框
// brush属性
QBrush brush;
brush.setColor(Qt::red); // 填充颜色
// brush.setStyle(Qt::SolidPattern); // 填充样式
// brush.setStyle(Qt::Dense7Pattern);
// brush.setStyle(Qt::CrossPattern);
brush.setStyle(Qt::FDiagPattern);
painter.setBrush(brush);
// 绘图
painter.drawRect(rect);
}


QBrush填充渐变颜色:

Qt中有三种渐变的效果,如下图所示:

1. QLinearGradient

        线性渐变颜色,可以指定一个起点颜色,终点颜色,还可以指定中间颜色,起点和终点之间可以进行插值计算,得到线性渐变的填充颜色。

void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及绘图设备
painter.setRenderHint(QPainter::Antialiasing); // 绘画普通图形启用反走样, 即开启抗锯齿
painter.setRenderHint(QPainter::TextAntialiasing); // 绘画文字反走样, 即开启抗锯齿
int width = this->width(); // 获取绘图区域的大小
int height = this->height();
QRect rect(width/4, height/4, width/2, height/2); // 中间区域矩形框
QLinearGradient linearGrident(width/4, height/4, width/2, height/2); // 指定渐变区域
linearGrident.setColorAt(0, Qt::red);
linearGrident.setColorAt(0.5, Qt::yellow);
linearGrident.setColorAt(1, Qt::blue);
// brush属性
QBrush brush;
painter.setBrush(linearGrident);
// 绘图
painter.drawRect(rect);
}

填充效果:

2.QConicalGradient: 圆锥形渐变,即围绕一个中心点逆时针生成渐变颜色。

void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及绘图设备
painter.setRenderHint(QPainter::Antialiasing); // 绘画普通图形启用反走样, 即开启抗锯齿
painter.setRenderHint(QPainter::TextAntialiasing); // 绘画文字反走样, 即开启抗锯齿
int width = this->width(); // 获取绘图区域的大小
int height = this->height();
QConicalGradient gradient(width/2, height/2, 0); // 填充参数参数cx, cy, start_angle,
gradient.setColorAt(0, Qt::red); // 起始角度的位置,与线性渐变一样,也是采用相对位置
gradient.setColorAt(0.4, Qt::green);
gradient.setColorAt(0.6, Qt::yellow);
gradient.setColorAt(1, Qt::black);
painter.setBrush(gradient);
painter.drawRect(this->rect()); // 画圆的区域
}

填充效果:

3. QRadialGradient: 辐射渐变填充,有简单辐射渐变和扩展辐射渐变两种方式,简单辐射渐变是在一个圆内一个焦点和一个端点之间生成渐变颜色,扩展辐射渐变是在一个焦点圆和一个中心圆之间生成渐变颜色。

void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及绘图设备
painter.setRenderHint(QPainter::Antialiasing); // 绘画普通图形启用反走样, 即开启抗锯齿
painter.setRenderHint(QPainter::TextAntialiasing); // 绘画文字反走样, 即开启抗锯齿
int width = this->width(); // 获取绘图区域的大小
int height = this->height();
// 径向渐变 c_x, c_y, radius, fx, fy 其中fx,fy为焦点
// c_x, c_y是辐射的中心点,radius是辐射半径
QRadialGradient gradient(width/2, height/2, qMax(width/4, height/4), width/2, height/2); // 径向渐变
gradient.setColorAt(0, Qt::red);
gradient.setColorAt(1, Qt::black); // 这里使用的是逻辑坐标 0开始位置 1结束位置
// gradient.setSpread(QGradient::PadSpread); // 设置渐变区域之外的渐变方式,即延展方式
// gradient.setSpread(QGradient::RepeatSpread);
gradient.setSpread(QGradient::ReflectSpread);
painter.setBrush(gradient);
painter.drawRect(this->rect()); // 画圆的区域
}

同时,QRadialGradient需要通过setSpread()函数设置延展方式,也就是填充区域意外的填充方式,共有三种方式:

下面是填充的效果:

PadSpread:

RepeatSpread:

ReflectSpread:

QPainter绘制基本图形元件:

QPainter可以绘制包括点,直线,曲线,矩形,圆弧等各种基本线条。具体的函数以及参数可以参考Qt文档:(文档部分)

坐标系统和坐标变换:

QPainter在窗口上绘图的默认坐标是绘图设备的物理坐标,为了绘图方便,QPainter提供了一些坐标变换功能,通过平移,旋转等坐标变换,得到一个逻辑坐标系统,使用逻辑坐标系统在某些时候绘图会更加方便。

常用的坐标变换:
1. 平移变换:
void translate(dx, dy):表示将坐标系统的原点移动到(dx, dy)位置。移动的单位为像素。

2. 坐标旋转:

void rotate(angle): 将坐标系统绕坐标原点旋转指定的角度。angle>0表示顺势正旋转,angle<0表示逆时针旋转。

3.缩放:

void scale(sx, sy): 表示缩放,sx,sy表示沿着x,y轴的缩放比例。参数大于1表示放大,参数小于1表示缩小。

4. 状态保存于恢复:
在进行坐标变换的时候,QPainter内部会有一个坐标变换的矩阵,用save()函数保存坐标的状态。用restore()表示恢复保存的坐标状态。这两个函数必须配对使用。resetTransform表示复位所有的变换操作。

 例子:

void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及绘图设备
painter.setRenderHint(QPainter::Antialiasing); // 绘画普通图形启用反走样, 即开启抗锯齿
painter.setRenderHint(QPainter::TextAntialiasing); // 绘画文字反走样, 即开启抗锯齿
int width = this->width(); // 获取绘图区域的大小
int height = this->height();
// 生成五角星的五个顶点坐标
int radius = 100; // 半径
const double Pi = 3.1415926;
double deg = 360.0 / 5 * Pi / 180.0;
QPoint points[5] = {
QPoint(radius, 0),
QPoint(radius * cos(deg), radius * sin(deg)),
QPoint(radius * cos(2*deg), radius * sin(2*deg)),
QPoint(radius * cos(3*deg), radius * sin(3*deg)),
QPoint(radius * cos(4*deg), radius * sin(4*deg))
};
// 设置字体
QFont font;
font.setPointSize(12);
font.setBold(true);
painter.setFont(font);
// 设置画笔
QPen pen;
pen.setWidth(2); // 设置线宽
pen.setColor(Qt::blue); // 设置颜色
pen.setStyle(Qt::SolidLine); // 设置线型
pen.setCapStyle(Qt::FlatCap);
pen.setJoinStyle(Qt::BevelJoin);
painter.setPen(pen);
// 设置画刷
QBrush brush;
brush.setColor(Qt::red);
brush.setStyle(Qt::SolidPattern);
painter.setBrush(brush);
// painter_path, 可以重复使用
QPainterPath path;
path.moveTo(points[0]); // 起始点
path.lineTo(points[2]);
path.lineTo(points[4]);
path.lineTo(points[1]);
path.lineTo(points[3]);
path.closeSubpath(); // 闭合路径,相当于 path.lineTo(points[0]);
// 添加文本
path.addText(points[0], font, "1");
path.addText(points[1], font, "2");
path.addText(points[2], font, "3");
path.addText(points[3], font, "4");
path.addText(points[4], font, "5");
// 保存坐标状态
painter.save();
painter.translate(width/4, height/4); // 平移
painter.drawPath(path);
// 恢复坐标
painter.restore();
painter.translate(width/2, height/2); // 平移
painter.scale(0.6, 0.6); // 缩放,缩小操作
painter.rotate(30); // 旋转
painter.drawPath(path); // 这里的path重复利用了
}

绘制效果图:

QPainterPath可以记录几个点的连线过程,可以对绘制复杂图像的过程进行记录,便于重复使用。

 

posted @   Alpha205  阅读(791)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示