文章目录
- 绘画概述
- 绘制API
-
- [1. 图形](#1. 图形)
-
- [(1). 线段](#(1). 线段)
- [(2). 矩形](#(2). 矩形)
- [(3). 圆形](#(3). 圆形)
- [(4). 绘制文本](#(4). 绘制文本)
- [2. 工具](#2. 工具)
-
- [(1). 画笔](#(1). 画笔)
- [(2). 画刷](#(2). 画刷)
- [3. 绘制图片](#3. 绘制图片)
- 绘图设备
-
- [(1). QPixmap](#(1). QPixmap)
- [(2). QImage](#(2). QImage)
- [(3). QPicture](#(3). QPicture)
- 结束语
绘画概述
虽然 Qt 已经内置了很多的控件,但还是有很多时候需要"自定义"
Qt 提供了画图相关的API,可以允许我们在窗口上绘制任意的图形形状,来完成更复杂的界面设计。
绘图核心类
类 | 说明 |
---|---|
QPainter | 类似"画家"的概念 用来绘图的对象,提供了一系列 drawXXX 方法,允许我们绘制各种图形 |
QPaintDevice | "画板" 描述了 QPainter 把图形画到哪个对象上,QWidget 是 QPaintDevice 的子类 |
QPen | "画笔" 描述了 QPainter 画出来的线是什么样的 |
QBrush | "画刷" 描述了 QPainter 画出的图形其内部如何填充 |
绘图 API 的使用,一般不会在 QWidget 构造函数中使用,而是
使用事件机制
,编写在paintEvent
事件中
paintEvent
会在以下情况被触发
- 控件首次创建
- 控件被遮挡后,被解除遮挡,重现显现的时候
- 窗口最小化,再恢复
- 控件大小发生变化时
- 主动调用
repaint()
或者update()
方法(都是 QWidget的方法)所以要将绘图 API 放在
paintEvent
中,如果放在构造函数中,则发生上述情况,界面的绘制效果就无法确保符合预期了
绘制API
绘制图形逻辑都是编写在paintEvent
中
1. 图形
(1). 线段
绘制线段的API为drawLine()
,Qt 提供了很多重载版本
API | 说明 |
---|---|
drawLine(int x1, int y1, int x2, int y2) | (x1, y1)是线段一端的坐标 ,(x2, y2)是线段另一端的坐标,两点确定一条直线 |
drawLine(const QLineF &line) | QLineF的构造函数也是传入两个坐标,如QLineF(10.0, 80.0, 90.0, 20.0) |
drawLine(QPoint &p1, QPoint &p2) | 传入两个坐标,QPoint(100, 200) |
代码示例:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;//避免不必要的警告
//画家不用创建在堆上,栈上即可
//此处的this,是指定要在哪个界面绘画
QPainter painter(this);
painter.drawLine(QLineF(100.0, 100.0, 100.0, 300.0));
painter.drawLine(100, 100, 275, 275);
painter.drawLine(QPoint(100, 100), QPoint(300, 100));
}
(2). 矩形
绘制矩形的API为drawRect()
API | 说明 |
---|---|
drawRect(int x, int y, int width, int height) | (x, y)是矩形左上角的坐标,width 和 height分别是宽度和高度 |
Qt 的坐标是左手坐标系
代码示例:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;//避免不必要的警告
//矩形
QPainter painter(this);
painter.drawRect(100, 100, 300, 200);
}
(3). 圆形
绘制圆形的 API 为 drawEllipse()
API | 说明 |
---|---|
drawEllipse(const QPoint ¢er, int rx, int ry) | center 是圆心坐标,rx 和 ry 分别是圆形的外接矩形的宽度和高度 |
drawEllipse(int x, int y, int width, int height) | (x, y)是圆心坐标,width 和 height 含义同 rx 和 ry |
代码示例:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;//避免不必要的警告
//圆形
QPainter painter(this);
painter.drawEllipse(200, 200, 250, 150);
}
(4). 绘制文本
QPainter 也可以绘制文本
使用QPainter::drawText()
绘制文字
使用QPainter::setFont()
设置字体等信息
API | 说明 |
---|---|
drawText(int x, int y, const QString &text) | 文本 text 的左上角坐标为(x, y) |
drawText(const QPointF &position, const QString &text) | 用QPointF 封装坐标 |
drawText(const QRectF &rectangle, const QString &text) | 将 text 放入 rectangle矩形内显示 |
代码示例:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;//避免不必要的警告
//文本
QPainter painter(this);
//设置字体信息
QFont font("华文行楷", 20);
painter.setFont(font);
//绘制文本
painter.drawText(QRect(100, 100, 180, 200), "千里之行始于足下");
}
把文本设置在宽180px,高200px的矩形中
2. 工具
(1). 画笔
QPaint绘制图形时,是有默认的画笔的。但也可以自定义画笔。
QPen 定义了 QPainter 应该如何绘制形状、线条和轮廓。同时通过 QPen 设置画笔的线宽、颜色、样式、画刷
等
setWidth(int width)
:设置线宽setStyle(Qt::PenStyle style)
:设置画笔的风格QPen(const QColor &color)
:设置画笔的颜色
画笔的风格由 Qt::PenStyle
枚举
代码示例:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;//避免不必要的警告
//画笔
QPainter painter(this);
//初始化画笔,同时设置颜色
QPen pen(QColor(255, 0, 0));
//设置线宽
pen.setWidth(3);
//设置风格------虚线
pen.setStyle(Qt::DashLine);
//设置画笔
painter.setPen(pen);
//画圆
painter.drawEllipse(100, 100, 200, 100);
}
(2). 画刷
Qt 使用 QBrush
封装画刷操作 ,画刷大多用于填充。QBrush 定义了 QPainter 的填充模式,具有样式、颜色、渐变以及纹理
等属性
画刷的格式定义了填充的样式,使用 Qt::BrushStyle
枚举,默认值是 Qt::NoBrush(不进行任何填充)
设置画刷主要通过 setBrush(const QBrush &brush)
,参数为画刷对象
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;//避免不必要的警告
//画笔
QPainter painter(this);
//初始化画笔,同时设置颜色
QPen pen(QColor(255, 0, 0));
//设置线宽
pen.setWidth(3);
//设置风格------虚线
pen.setStyle(Qt::DashLine);
//设置画笔
painter.setPen(pen);
//画刷
QBrush brush(Qt::cyan);//青色
//设置风格
brush.setStyle(Qt::Dense1Pattern);
//设置画刷
painter.setBrush(brush);
//画圆
painter.drawEllipse(100, 100, 200, 100);
}
3. 绘制图片
Qt 提供了四个类来处理图像数据:QImage、QPixmap、QBitmap、QPicture
,都是常用的绘图设备。
QImage 主要用来处理 I/O处理,其对 I/O 处理操作进行了优化,而且可以用来直接访问和操作像素
QPixmap 主要用来在屏幕上显示图像,对图像在屏幕上显现进行了优化
QBitMap 是 QPixmap 的子类,用来处理颜色深度为1的图像,即只能显示黑白两种颜色
QPicture 用来记录并重演 QPainter 命令
QPainter图片操作
对图片的操作,同样在paintEvent()
事件处理函数中编写
绘制简单图片
图片资源的添加与管理,参看【Qt】QWidget 的qrc文件部分
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
QPainter painter(this);
//绘图
painter.drawPixmap(0, 0, QPixmap(":/6.jpg"));
}
平移图片
平移图片实际是通过改变坐标来实现的,QPainter 提供了 translate()
函数来实现坐标原点的改变
其函数原型如下:
参数(dx, dy)是将坐标原点平移到到(dx, dy)处
代码示例:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
//平移图片
QPainter painter(this);
painter.translate(100, 100);
//绘图
painter.drawPixmap(0, 0, QPixmap(":/6.jpg"));
}
缩放图片
drawPixmap()
的重载函数就可以实现图片的放大和缩小
通过 width 和 height 控制图片的宽度和高度
代码示例:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
//缩放图片
QPainter painter(this);
painter.drawPixmap(0, 0, QPixmap(":/6.jpg"));//图片原始大小
//将图片缩放成 100 * 100
painter.drawPixmap(400, 400, 100, 100, QPixmap(":/6.jpg"));
}
- 旋转图片
图片的旋转使用的是 QPainter 的 rotate
函数,默认是以原点为中心进行旋转。如果要改变旋转的中心,可以使用 translate()
直接
rolate
旋转,会导致原先显示界面的图形被旋转到显示界面外
代码示例:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
//旋转图片
QPainter painter(this);
painter.translate(200, 200);//先旋转原点
painter.rotate(180);//旋转180度
painter.translate(-200, -200);//旋转回来
painter.drawPixmap(0, 0, QPixmap(":/6.jpg"));
}
- 保存/加载画家状态
在绘制图形的过程中,可以通过save()
函数保存画家的状态,如当前原点坐标,旋转情况;使用restore()
还原画家状态
代码示例:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
//保存/加载画家状态
QPainter painter(this);
painter.drawEllipse(100, 100, 100, 100);//画个圆
painter.translate(200, 200);//平移原点
painter.save();//保存画家状态
//新画一个圆
painter.drawEllipse(100, 100, 100, 100);
painter.translate(300, 300);//再平移
painter.restore();//此时恢复画家状态
//再画一个圆
painter.drawEllipse(100, 100, 100, 100);
}
第二个圆和第三个圆重合了,因为把加载了之前的画家状态
绘图设备
上述代码都是使用 QWidget
作为绘图设备,Qt 还提供了 如下三个绘图设备
QPixmap
:用于在显示器上显示图片QImage
:用于对图片进行像素级修改QPicture
:用于对 QPainter 的一系列操作进行存档,是实现回放的一种方式
(1). QPixmap
QPixmap核心特性:
- 使用 QPainter 直接在上面进行绘制图形
- 通过文件路径加载并显示图片,或保存图片
- 搭配
QPainter
的drawPixmap()
函数,可以把这个图片绘制到 QLabel、QPushButton等控件上 - 和系统/显示设备强相关,不同系统/显示设备下,QPixmap 的显示可能会有所差别
代码示例:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//绘制图形并保存
//Pixmap绘图设备,尺寸设置为500 * 500
QPixmap pix(500, 500);
QPainter painter(&pix);//实例化画家对象
painter.setPen(QPen(Qt::red));//设置画笔颜色
painter.drawEllipse(100, 100, 200, 100);
//保存绘制的图片
pix.save("C:\\Users\\Lenovo\\Desktop\\code\\text.png");
}
(2). QImage
QImage 核心特性:
- 使用 QPainter 直接在上面进行绘制图形
- 通过文件路径加载并显示图片
- 能够针对图片进行像素级别的操作(操作某个指定的像素)
- 独立于硬件的绘制系统,能够在不同系统之上提供已知的显示
QImage 的构造函数,还可以设置绘图格式
代码示例:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//绘图设置的大小为500*500,绘图格式为:QImage::Format_RGB32
QImage img(500, 500, QImage::Format_RGB32);
img.fill(Qt::white);//设置背景色为白色,默认为黑色
QPainter painter(&img);
painter.setPen(QPen(Qt::cyan));//设置画笔颜色为青色
painter.drawEllipse(100, 100, 100, 100);
img.save("C:\\Users\\Lenovo\\Desktop\\code\\img.png");
}
QImage 也可以用于对图片像素进行修改
- 通过
setPixel()
设置某个像素的颜色值 - 使用 qRgb 表示一个具体的颜色
代码示例:
cpp
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
QPainter painter(this);
QImage img;
img.load(":/1.jpg");//加载图片
//修改像素点
for(int i = 100; i < 200; ++i)
{
for(int j = 100; j < 200; ++j)
{
QRgb rgb = qRgb(0, 255, 0);
img.setPixel(i, j, rgb);
}
}
painter.drawImage(0, 0, img);
}
(3). QPicture
QPicture 核心特性:
- 使用 QPainter 直接在上面进行绘制图形
- 通过文件路径加兹安并显示图片
- 能够记录 QPainter 的操作步骤
- 独立于硬件的绘制系统,能够在不同系统之上提供一致的显示
QPicture 类似很多游戏的 Replay(回放功能)
此处的Replay并不是把整个游戏画面都录制下来,而是记录了地图中发生的所有事件(地图元素,玩家单位操作,中立生物行为等...)
当回放 Reply 时就是把上述记录的事件再一条条的执行一遍即可还原之前的游戏场景
如果要记录下 QPainter 的命令,首先要使用 QPainter::begin()
函数,将QPicture 示例作为参数传递,以便告诉系统开始记录,记录完毕后使用 QPainter::end()
终止
复现时,使用QPicture::load()
加载记录,使用QPainter::drawPicture()
复现绘图
代码示例:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//QPicture 复现绘图
QPainter painter(this);
QPicture pic;
//开始记录
painter.begin(&pic);
painter.setPen(QPen(Qt::blue));
painter.drawEllipse(200, 200, 150, 150);
//终止记录
painter.end();
//保存记录
pic.save("C:\\Users\\Lenovo\\Desktop\\code\\pic.png");
}
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
//QPicture 复现绘图
QPainter painter(this);
QPicture pic;
//加载记录
pic.load("C:\\Users\\Lenovo\\Desktop\\code\\pic.png");
//复现
painter.drawPicture(0, 0, pic);
}
如此,每次显示窗口时,都会复现 QWidget 构造函数中的绘图操作
结束语
Qt 对于界面的优化和美化,还涉及很多知识
- Qt 动画
- Qt 3D 图形
- QQuick
- 第三方控件库
- Qt Design Studio
这些都是偏向"设计美工"方面的内容
以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。