[Qt] QPainter | Qpen | QPixmap
目录
绘图
1、基本概念
2、绘制各种形状
(1)绘制线段
(2)绘制矩形
(3)绘制圆形
(4)绘制文本
(5)设置画笔
【画笔的使用】
(6)设置画刷
3、绘制图片
(1) 绘制简单图片
(2)平移图片
(3)缩放图片
(4)旋转图片
4、其他设置
(1)移动画家位置
(2)保存 / 加载画家的状态
5、特殊的绘图设备
(1)QPixmap
(2)QImage
(3)QPicture
更多参考内容:
• 官⽅⽂档中的Qt Style Sheets Examples 章节
• https://github.com/GTRONICK/QSS
绘图
1、基本概念
虽然 Qt 已经内置了很多的控件,但是不能保证现有控件就可以应对所有场景。很多时候我们需要更强的 “自定制” 能力。
Qt 提供了画图相关的 API,允许我们在窗口上绘制任意的图形形状来完成更复杂的界面设计。
- 所谓的 “控件” 本质上也是通过画图的方式画上去的。
- 画图 API 和控件之间的关系,可以类比成机器指令和高级语言之间的关系。
- 控件是对画图 API 的进一步封装,画图 API 是控件的底层实现。
(1)绘图 API 核心类
类 | 说明 |
QPainter | "绘画者" 或者 "画家". |
QPaintDevice | "画板". |
QPen | "画笔". |
QBrush | "画刷". |
绘图 API 的使用一般不会在 QWidget 的构造函数中使用,而是要放到 paintEvent 事件中。
paintEvent 会在以下情况下被触发:
- 控件首次创建。
- 控件被遮挡,再解除遮挡。
- 窗口最小化,再恢复。
- 控件大小发生变化时。
- 主动调用 repaint() 或者 update() 方法(这两个方法都是 QWidget 的方法)。
- ... ...
2、绘制各种形状
(1)绘制线段
void drawLine(const QPoint &p1, const QPoint &p2);
参数:
p1:绘制起点坐标
p2:绘制终点坐标
void drawLine ( int x1, int y1, int x2, int y2 );
参数:
x1,y1:绘制起点坐标
x2,y2:绘制终点坐标
示例:
A. 在 "widget.h" 头文件中声明绘图事件
void paintEvent(QPaintEvent* event);
B. 在 "widget.cpp" 文件中重写 paintEvent() 方法
void Widget::paintEvent(QPaintEvent *event)
{
(void) event;
// 绘图工作就会放到这里来执行.
QPainter painter(this);
// 画一个线段.
painter.drawLine(20, 20, 200, 20);
painter.drawLine(QPoint(20, 100), QPoint(200, 100));
painter.drawLine(20, 20, 100, 300);
}
实现效果如下:
(2)绘制矩形
void QPainter::drawRect(int x, int y, int width, int height);
参数:
x:窗⼝横坐标;
y:窗⼝纵坐标;
width:所绘制矩形的宽度;
height:所绘制矩形的⾼度;
示例:
// 画一个矩形.
painter.drawRect(100, 100, 300, 200);
实现效果如下:
(3)绘制圆形
void QPainter::drawEllipse(const QPoint ¢er, int rx, int ry)
参数:
center:中⼼点坐标
rx:横坐标
ry:纵坐标
示例:
// 画圆形.
painter.drawEllipse(200, 200, 400, 100);
实现效果:
(4)绘制文本
QPainter 类中不仅提供了绘制图形的功能,还可以使用 QPainter::drawText() 函数来绘制文字,也可以使用 QPainter::setFont() 设置字体等信息。
示例:
QFont font("微软雅黑", 24);
painter.setFont(font);
// 绘制文本.
painter.drawText(0, 100, "hello");
实现效果:
(5)设置画笔
QPainter 在绘制时,是有一个默认的画笔的。在使用时也可以自定义画笔。在 Qt 中,QPen 类中定义了 QPainter 应该如何绘制形状、线条和轮廓。同时通过 QPen 类可以设置画笔的线宽、颜色、样式、画刷等。
画笔的颜色可以在实例化画笔对象时进行设置,画笔的宽度是通过 setWidth() 方法进行设置,画笔的风格是通过 setStyle() 方法进行设置,设置画刷主要是通过 setBrush() 方法。
- 设置画笔颜色:QPen::QPen(const QColor &color) 画笔的颜色主要是通过 QColor 类设置;
- 设置画笔宽度:void QPen::setWidth(int width)
- 设置画笔风格:void QPen::setStyle(Qt::PenStyle style)
画笔的风格有:
【画笔的使用】
QPen pen;
// 设置成红色的线条
pen.setColor(QColor(255, 0, 0));
// 设置线条的粗细.
pen.setWidth(5);
// 设置线条的风格
pen.setStyle(Qt::DashLine);
// 让 painter 对象应用 pen 对象
painter.setPen(pen);
// 画圆形.
painter.drawEllipse(200, 200, 400, 100);
实现效果如下:
(6)设置画刷
在 Qt 中,画刷是使用 QBrush 类来描述,画刷大多用于填充。QBrush 定义了 QPainter 的填充模式,具有样式、颜色、渐变以及纹理等属性。
画刷的格式中定义了填充的样式
使用 Qt::BrushStyle 枚举,默认值是 Qt::NoBrush,也就是不进行任何填充。
可以通过 Qt 助手查找画刷的格式。如下图示:
设置画刷主要通过 void QPen::setBrush(const QBrush &brush) 方法,其参数为画刷的格式。
示例:
QBrush brush;
brush.setColor(QColor(0, 255, 0));
// brush.setStyle(Qt::SolidPattern);
brush.setStyle(Qt::CrossPattern);
painter.setBrush(brush);
实现效果:
3、绘制图片
Qt 提供了四个类来处理图像数据:QImage、QPixmap、QBitmap 和 QPicture
- 其中QImage主要用来进行 I/O 处理,它对 I/O 处理操作进行了优化,而且可以用来直接访问和操作像素;
- QPixmap 主要用来在屏幕上显示图像,它对在屏幕上显示图像进行了优化;
- QBitmap 是 QPixmap 的子类,用来处理颜色深度为 1 的图像,即只能显示黑白两种颜色;
- QPicture 用来记录并重演 QPainter 命令。
(1) 绘制简单图片
A. 新建 Qt 项目,基类选择 QWidget,项目名称为 QPainter。
在 "widget.h" 头文件中声明绘画事件
void paintEvent(QPaintEvent *event);
B. 添加资源文件
首先准备一些图片资源文件,并将这些图片资源文件放在同一个文件夹中,将该文件夹复制到本项目中:
c. 点击 “构建并运行” 按钮,将资源文件添加到项目中
d. 在 "widget.cpp" 文件中实现画图片功能
void Widget::paintEvent(QPaintEvent *)
{
//实例化 画家对象
QPainter painter(this);
//画图片
painter.drawPixmap(0,0,QPixmap(":/picture/1.jpg"));
}
(2)平移图片
平移图片实际是通过改变坐标来实现。QPainter 类中提供了 translate() 函数来实现坐标原点的改变。
示例:
painter.translate(100,100);
(3)缩放图片
示例:
(4)旋转图片
图片的旋转使用的是 QPainter 类中的 rotate() 函数,它默认是以原点为中心进行旋转的。如果要改变旋转的中心,可以使用 translate() 函数完成。
示例:
QPainter painter(this);
QPixmap pixmap(":/picture/2.jpeg");
painter.rotate(180);
painter.translate(-800,-600);
painter.drawPixmap(100,100,400,300,pixmap);
实现效果:
4、其他设置
(1)移动画家位置
有时候在绘制多个图形时,想使用同一坐标位置,那么绘制出来的图形肯定会重合,此时,可以通过移动画家的位置来使图形不发生重合。
【未移动画家位置】
实现效果如下:
【移动画家位置】
使用 translate 移动画家所在位置:
实现效果如下:
(2)保存 / 加载画家的状态
在绘制图形的过程中,可以通过 save() 函数来保存画家的状态,使用 restore() 函数还原画家状态。
save() 函数原型如下:
- void QPainter::save();
restore() 函数原型如下:
- void QPainter:: restore ();
示例:
实现效果如下:
说明:
在画第三个圆之前,由于还原了画家的状态,所以此时画家的位置坐标会移动到画家状态保存的地方,所以在绘制第三个圆的位置时实际是和第二个圆发生了重叠。
5、特殊的绘图设备
前面的代码中我们是使用 QWidget 作为绘图设备,在 Qt 中还存在下列三个比较特殊的绘图设备。
- QPixmap 用于在显示器上显示图片
- QImage 用于对图片进行像素级修改
- QPicture 用于对 QPainter 的一系列操作进行存档
(1)QPixmap
QPixmap 核心特性:
- 使用 QPainter 直接在上面进行绘制图形。
- 通过文件路径加载并显示图片。
- 搭配 QPainter 的 drawPixmap() 函数,可以把这个图片绘制到⼀个 QLabel、QPushButton 等控件上。
- 和系统 / 显示设备强相关,不同系统 / 显示设备下,QPixmap 的显示可能会有所差别。
示例:
实现效果:
(2)QImage
QImage 的核心特性:
- 使用 QPainter 直接在上面进行绘制图形。
- 通过文件路径加载并显示图片。
- 能够针对图片进行像素级别的操作(操作某个指定的像素)。
- 独立于硬件的绘制系统,能够在不同系统之上提供一致的显示。
【QImage 作为绘图设备的使用】
【QImage 绘图时对像素的修改】
A. 新建 Qt 项目,添加图片资源文件到项目中
B. 在 widget.h 头文件中声明绘图事件
C. 在 widget.cpp 文件中重写绘图事件,使用 QImage 对图片像素进行修改
- 通过 setPixel 设置某个像素的颜色值
- 使用 qRgb 表示一个具体的颜色
#include "widget.h"
#include <QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
}
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this); // 实例化画家对象
QImage img;
img.load(":/picture/3.jpg"); // 加载图片
// 修改像素点
for(int i = 100; i < 200; i++)
{
for(int j = 100; j < 200; j++)
{
QRgb rgb = qRgb(0, 0, 255);
img.setPixel(i, j, rgb);
}
}
painter.drawImage(0, 0, img);
}
D. 执行效果
修改像素之后
(3)QPicture
QPicture 核心特性:
- 使用 QPainter 直接在上面进行绘制图形。
- 通过文件路径加载并显示图片。
- 能够记录 QPainter 的操作步骤。
- 独立于硬件的绘制系统,能够在不同系统之上提供⼀致的显示。
注意 :QPicture 加载的必须是自身的存档文件,而不能是任意的 png, jpg 等图片文件。
如果要记录下 QPainter 的命令
- 首先要使用 QPainter::begin() 函数,将 QPicture 实例作为参数传递进去,以便告诉系统开始记录
- 记录完毕后使用 QPainter::end() 命令终止。
示例:
展示效果如下:
通过 QPicture 重现绘图指令后,实现的效果如下:
💡:
Qt 中对于界面的优化美化,还涉及到很多其他的话题,如果在工作中如果涉及到了,再针对性学习即可。
- Qt 动画
- Qt 3D 图形
- QQuick
- 使用第三方控件库
- Qt Design Studio
- ... ...