概述
Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制。整个绘图系统基于QPainter,QPainterDevice和QPaintEngine三个类。
QPainter用来执行绘制的操作;
QPaintDevice是一个二维空间的抽象,这个二维空间允许QPainter在其上面进行绘制,也就是QPainter工作的空间;
QPaintEngine提供了画笔(QPainter)在不同的设备上进行绘制的统一的接口。
QPaintEngine类应用于QPainter和QPaintDevice之间,通常对开发人员是透明的。除非你需要自定义一个设备,否则你是不需要关心QPaintEngine这个类的。我们可以把QPainter理解成画笔;把QPaintDevice理解成使用画笔的地方,比如纸张、屏幕等;而对于纸张、屏幕而言,肯定要使用不同的画笔绘制,为了统一使用一种画笔,我们设计了QPaintEngine类,这个类让不同的纸张、屏幕都能使用一种画笔。
下图给出了这三个类之间的层次结构:
上面的示意图告诉我们,Qt 的绘图系统实际上是,使用QPainter在QPainterDevice上进行绘制,它们之间使用QPaintEngine进行通讯(也就是翻译QPainter的指令)。
1. 声明绘图事件(widget.h)
新建一个项目,在widget.h
中声明绘图事件void paintEvent();
//绘图事件
void paintEvent(QPaintEvent *);
2. 重写绘图事件(widget.cpp)
在widget.cpp
中重写绘图事件
#include <QPainter>//画家类
……
void Widget::paintEvent(QPaintEvent *)
{
}
2.1. 声明画家对象
首先实例化画家对象,将其绘图设备指定为当前窗口this
//实例化画家对象 this指定的是绘图的设备--->在当前窗口进行绘画
QPainter painter(this);
2.2. 实现画线、圆、矩形和文字
画线、圆、矩形和文字:
- 画线——
drawLine();
- 画圆(椭圆)——
drawEllipse();
- 画矩形——
drawRect();
- 画文字——
drawText();
函数后面的参数有不同的实现方式,根据Qt中的提示自行决定即可
//画线
painter.drawLine(QPoint(0,0),QPoint(100,100));
//画圆 椭圆
painter.drawEllipse(QPoint(100,100),50,50);
//画矩形
painter.drawRect(QRect(20,20,50,50));
//画文字
painter.drawText(QRect(10,200,100,50),"好好学习,天天向上");
效果如下:
2.3. 设置画笔
设置画笔:
- 设置画笔颜色——
pen(QColor());
- 设置画笔宽度——
setWidth();
- 设置画笔风格——
setStyle();
- 使用画笔——
setPen();
注意:
- 无论是设置画笔的颜色、宽度还是风格,都要在使用这支笔之前设置
- 笔的默认宽度是1,设为0的话宽度显示也是1
//设置画笔
QPen pen(QColor(255,0,0));
//设置画笔的宽度
pen.setWidth(3);
//设置画笔风格
pen.setStyle(Qt::DotLine);
//让画家 使用这个笔
painter.setPen(pen);
效果如下:
2.4. 设置笔刷
设置笔刷:
- 设置笔刷颜色——
brush(QColor());
或brush(Qt::green);
- 设置笔刷风格——
setStyle();
- 使用笔刷——
setBrush();
//设置画刷
//QBrush brush(QColor(0,255,0));
QBrush brush(Qt::green);
//设置画刷风格
brush.setStyle(Qt::CrossPattern);
//让画家使用画刷
painter.setBrush(brush);
效果如下:
3. 参考程序文件
4. QPainter高级设置
4.1. 抗锯齿效果
我们通过设置画家的抗锯齿效果setRenderHint()
,可以得到不同精细程度的画,但是相应的,精度越高的画效率的越低。
QPainter painter(this);
//画两个圆
painter.drawEllipse(QPoint(100,50),50,50);
//设置 抗锯齿能力 效率较低
painter.setRenderHint(QPainter::Antialiasing);
painter.drawEllipse(QPoint(200,50),50,50);
效果如下:
可以看出右边的圆,锯齿较少,效果较好
4.2. 对画家进行移动
画家的移动是基于之前保存的画家状态的,通过translate
可以移动画家,后面绘制的图形都是基于当前画家位置绘制的,通过restore()
我们可以回复到上一个保存的画家状态。
//画一个矩形
painter.drawRect(QRect(20,20,50,50));
//移动画家
painter.translate(100,0);
//保存画家状态
painter.save();
painter.drawRect(QRect(20,20,50,50));
painter.translate(100,0);
//还原画家保存状态
painter.restore();
//最后一个和第二个矩形重叠了
painter.drawRect(QRect(20,20,50,50));
效果如下:
根据代码我们可以分析出,第二个和第三个矩形重合了,因为他们都是基于同一个画家位置绘制的。
5. 高级设置参考代码
高级设置
// QPainter painter(this);
// //画两个圆
// painter.drawEllipse(QPoint(100,50),50,50);
// //设置 抗锯齿能力 效率较低
// painter.setRenderHint(QPainter::Antialiasing);
// painter.drawEllipse(QPoint(200,50),50,50);
// //画一个矩形
// painter.drawRect(QRect(20,20,50,50));
// //移动画家
// painter.translate(100,0);
// //保存画家状态
// painter.save();
// painter.drawRect(QRect(20,20,50,50));
// painter.translate(100,0);
// //还原画家保存状态
// painter.restore();
// //最后一个和第二个矩形重叠了
// painter.drawRect(QRect(20,20,50,50));
6. 手动调用绘图事件
6.1. 利用画家画图片
注意在Qt中的图片是Pixmap,因此画图片用drawPixmap()
函数
QPainter painter(this);
painter.drawPixmap(0,0,QPixmap(":/Image/Luffy.png"));
效果如下:
6.2. 手动调用绘图事件
这里我们想点击按钮,实现图片右移。我们先定义一个变量posX
代替图片起始点横坐标。
int posX=0;
painter.drawPixmap(posX,0,QPixmap(":/Image/Luffy.png"));
然后我们使用信号槽事件,连接按钮和绘图事件,其中手动调用绘图事件使用update()
函数,并更新posX的值
//点击移动按钮,移动图片
connect(ui->pushButton,&QPushButton::clicked,[=](){
posX+=20;
//如果要手动调用绘图事件 用update更新
update();
});
同时为了防止图片超出屏幕。我们在绘图事件中添加一个条件判断,当超过屏幕时,将其置0
QPainter painter(this);
//如果超出了屏幕 从0开始
if(posX>this->width()){
posX=0;
}
painter.drawPixmap(posX,0,QPixmap(":/Image/Luffy.png"));
效果如下:
此处为语雀视频卡片,点击链接查看:手动调用绘图事件.mp4