Qt关于二维图形的绘制一些个人理解和心得

1. QPaintEngine ,QPainterDvice , QPainter的关系

a. QPaintEngine跟平台相关,提供了一些接口给QPainter使用,可用于 QPainter 在不同的设备上进行绘制,如继承自QPaintEngine的QRasterPaintEngine(一般windows),QX11PaintEngine(linux)

b. QPainterDevice是一个可使用QPainter在之上进行绘制的基类,如QWidget,QImage,QPixmap等都是继承自QPainterDevice,有实际的高度height、宽度width,会将绘制出来的结果保存起来,所以会占用内存。另外QPainterDevice的虚函数QPaintEngine* paintEngine()返回了这个设备相关的QPaintEngine指针。

c.QPainter是一个与平台无关的负责绘制的类,它在绘制时必须要绑定一个QPainterDevice设备,这样才能在这个设备上进行绘制,在绘制一个图形时,通过它的接口实际它会调用与之绑定的QPainterDevice的QPaintEngine指针去实现具体的绘制。

2.关于QPainter

由上可知QPainter其实是与平台不相关的一个负责绘制的类,里面实现了几乎所有图形绘制的接口,包括绘制点、线、矩形、弧形、饼状图、多边形、贝塞尔弧线等 。并且还提供了反走样等对绘制效果就行修正的高级设置,同时还可以通过它对设备上的任意位置进行快速绘制,接下来就来讲讲QPainter的具体用法。

i.在哪里可以使用QPainter?

一般地,QPainter通常在paintEvent事件中使用的最多,也是Qt基于QWidget进行绘制开发的最基本的显示实现情况,所有基于QWidget的Qt控件,其实都是通过paintEvent中用QPainter进行绘制显示的。其他使用的情况如QPixmap,QImage设备的绘制也是可以通过QPainter进行绘制的,例如:

QPixmap pixmap(QSize(300,300));
QPainter painter(&pixmap);
painter.setPen(QColor(Qt::red));
painter.drawRect(QRect(10,10,200,200));

这样就实现了在QPixmap上绘制了一个红色边线矩形,并保存到了pixmap中(不会被局限于QWidget的paintEvent中,可以试试不在QWidget的paintEvent中进行绘制,看会有什么结果?)

ii.QPainter的绘制接口

绘制接口Qt的帮助文档中一大推,输入QPainter查看拿来用就好 这里介绍一些注意事项。

ii-1.关于边线的问题

我们在使用QPainter进行绘制的时候,默认边线的宽度是1px宽, 如果我 们绘制一个矩形,并设置线的宽度为6,其实结果矩形的线条会和填充区域有线宽一般的重叠部分(这里就是3),

QPen p(painter.pen());
p.setWidth(6);
painter.setPen(p);
painter.drawRect(QRect(10,10,200,200));

可能想要的预期结果 vs 实际的结果:

黄色区域即实际显示出来的填充区域

所有的描边都是这样的,线宽的一般会和填充部分有重叠(这个在处理线条带有alpha时如果线宽很大然后又有填充值那么就会出现第三种颜色)。如果要做到不重叠,就需要计算到这个线宽值把填充和描边分开绘制(坑啊…)

ii-2.关于QWidget的update和repaint

关于update和repaint,都可以实现用户调用后触发QWidget的paintEvent事件(除非自己取消的Qt的双缓存机制 自己去渲染),区别在于,前者是通过消息队列的方式产生驱动绘制事件的执行,后者是直接产生执行绘制事件。并且以界面绘制次数频率等考虑 ,update是要优于repaint的它会进行一些重复绘制请求的合并,从而降低绘制的频率,而repaint就是很老实,你调用多少次他就会马上执行绘制多少次,所以很容易不小心就会导致界面卡死。这下知道调用哪一个吧?你懂得。

ii-3.关于qpainter的save和restore

是否有过绘制很多不同样式颜色图形的经历?如果给你这样的需求:

1.先在当前位置绘制一个无边线的红色填充的矩形,

2.移动QPointF(20,20)然后再绘制一个黑色边线的无填充矩形

3.再回到之前的位置绘制一个无边线的绿色矩形

可能最开始的时候都是这样写的

//无边线的红色填充的矩形
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::red);
painter.drawRect(rect());

//黑色边线的无填充矩形
painter.transform(20,20);
painter.setPen(Qt::Black);
painter.setBrush(Qt::NoBrush);
painter.drawRect(rect());


//无边线的红色填充的矩形
painter.transform(-20,-20);  //移动回去
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::green);
painter.drawRect(rect());

可能这个列子不是那么适合,但这里我想说的是其实在绘制第二个矩形前,可以加上painter.save()以保留当前painter的状态,然后在绘制完成后painter.restore()恢复状态,从而就不用再在绘制第三个矩形前调用painter.transform(-20,-20)和painter.setPen(Qt::NoPen);修改后如下:

//无边线的红色填充的矩形
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::red);
painter.drawRect(rect());

//保存当前的painter状态
painter.save();

//黑色边线的无填充矩形
painter.transform(20,20);
painter.setPen(Qt::Black);
painter.setBrush(Qt::NoBrush);
painter.drawRect(rect());

//还原painter状态
painter.restore();

//无边线的红色填充的矩形
painter.setBrush(Qt::green);
painter.drawRect(rect());

暂时就分享这些 以后再添加更多的知识吧 谢谢。

(以上为个人理解,仅供参考哈,原文https://www.jdeverything.com/index.php/2020/04/21/qt%e5%85%b3%e4%ba%8e%e4%ba%8c%e7%bb%b4%e5%9b%be%e5%bd%a2%e7%9a%84%e7%bb%98%e5%88%b6/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值