目录
1. 基本概念
虽然 Qt 已经内置了很多的控件, 但是不能保证现有控件就可以应对所有场景.
很多时候我们需要更强的 "自定制" 能力.
Qt 提供了画图相关的 API, 可以允许我们在窗上绘制任意的图形形状, 来完成更复杂的界面设计.
所谓的 "控件" , 本质上也是通过画图的方式画上去的.
- 画图 API 和 控件 之间的关系, 可以类比成机器指令和高级语言之间的关系.
控件是对画图 API 的进一步封装; 画图 API 是控件的底层实现.
绘图 API 核心类:
类 | 说明 |
QPainter | "绘画者" 或者 "画家". 用来绘图的对象, 提供了⼀系列 drawXXX 方法, 可以允许我们绘制各种图形. |
QPaintDevice | "画板". 描述了 QPainter 把图形画到哪个对象上. 像我们之前用过的 QWidget 也是⼀种 QPaintDevice (QWidget 是 QPaintDevice 的子类) . |
QPen | "画笔". 描述了 QPainter 画出来的线是什么样的. |
QBrush | "画刷". 描述了 QPainter 填充一个区域是什么样的. |
绘图 API 的使用, 一般不会在 QWidget 的构造函数中使用, 而是要放到 paintEvent 事件中.
🌴关于 paintEvent
paintEvent 会在以下情况下被触发:
- 控件首次创建.
- 控件被遮挡, 再解除遮挡.
- 窗口最小化, 再恢复
- 控件大小发生变化时.
- 主动调用 repaint() 或者 update() 方法. (这两个方法都是 QWidget 的方法).
- ......
因此, 如果把绘图 api 放到构造函数中调用, 那么一旦出现上述的情况, 界面的绘制效果就无法确保符合预期了.
2. 绘制各种形状
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:绘制终点坐标
示例:
1、在 "widget.h" 头文件中声明绘图事件;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
// 声明绘图事件
void paintEvent(QPaintEvent *event);
private:
Ui::Widget *ui;
};
2、在 "widget.cpp" 文件中重写 paintEvent() 方法;
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
// 实例化画家对象 this:表示的是在当前窗口中绘画,即绘图设备
QPainter painter(this);
// 1. 画一条线
// painter.drawLine(50, 50, 500, 50);
// 2. 再画一条线
painter.drawLine(QPoint(50, 50), QPoint(500, 50));
}
实现效果如下:
2.2 绘制矩形
void QPainter::drawRect(int x, int y, int width, int height);
参数:
- x:窗口横坐标;
- y:窗口纵坐标;
- width:所绘制矩形的宽度;
- height:所绘制矩形的高度;
示例:
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
// 实例化画家对象 this:表示的是在当前窗口中绘画,即绘图设备
QPainter painter(this);
// 绘制矩形
painter.drawRect(100, 100, 300, 150);
}
实现效果如下:
2.3 绘制圆形
void QPainter::drawEllipse(const QPoint ¢er, int rx, int ry)
参数:
- center:中心点坐标
- rx:横坐标
- ry:纵坐标
示例:
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
// 实例化画家对象 this:表示的是在当前窗口中绘画,即绘图设备
QPainter painter(this);
// 绘制圆
painter.drawEllipse(QPoint(300, 300), 100, 100);
}
实现效果如下:
2.4 绘制文本
QPainter类 中不仅提供了绘制图形的功能,还可以使用 QPainter::drawText() 函数来绘制文字,也可以使用 QPainter::setFont() 设置字体等信息。
示例:
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
// 实例化画家对象 this:表示的是在当前窗口中绘画,即绘图设备
QPainter painter(this);
// 设置字体
QFont font("华文行楷", 25);
painter.setFont(font);
// 设置画笔颜色
painter.setPen(Qt::blue);
// 画文字
painter.drawText(300, 250, "草长莺飞");
}
实现效果如下:
2.5 设置画笔
QPainter 在绘制时,是有一个默认的画笔的。在使用时也可以自定义画笔。在 Qt 中,QPen类中定义了 QPainter 应该如何绘制形状、线条和轮廓。同时通过 QPen类 可以设置画笔的线宽、颜色、样式、画刷等。
画笔的颜色可以在实例化画笔对象时进行设置,画笔的宽度是通过 setWidth() 方法进行设置,画笔的风格是通过setStyle()方法进行设置,画笔的颜色主要是通过 QColor 类设置,设置画刷主要是通过 setBrush() 方法。
- 设置画笔颜色:QPen::QPen(const QColor &color)
- 设置画笔宽度:void QPen::setWidth(int width)
- 设置画笔风格:void QPen::setStyle(Qt::PenStyle style)
画笔的风格有:
示例:画笔的使用
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
// 实例化画家对象 this:表示的是在当前窗口中绘画,即绘图设备
QPainter painter(this);
// 设置画笔
QPen pen(QColor(0, 255, 255));
// 设置画笔宽度
pen.setWidth(5);
// 设置画笔风格
pen.setStyle(Qt::DashLine);
// 让画家使用画笔
painter.setPen(pen);
// 绘制圆
painter.drawEllipse(QPoint(300, 300), 100, 100);
}
实现效果如下:
2.6 设置画刷
在 Qt 中,画刷是使用 QBrush类 来描述,画刷大多用于填充。QBrush定义了QPainter的填充模式,具有样式、颜色、渐变以及纹理等属性。
画刷的格式中定义了填充的样式,使用 Qt::BrushStyle 枚举,默认值是 Qt::NoBrush,也就是不进行任何填充。可以通过 Qt 助手查找画刷的格式。如下图示:
设置画刷主要通过 void QPen::setBrush(const QBrush &brush) 方法,其参数为画刷的格式。
示例:
void Widget::paintEvent(QPaintEvent *event)
{
(void)event;
// 实例化画家对象 this:表示的是在当前窗口中绘画,即绘图设备
QPainter painter(this);
// 设置画刷,给封闭图形填充颜色
QBrush brush(QColor(255, 0, 255));
// 设置画刷风格
brush.setStyle(Qt::DiagCrossPattern);
// 让画家使用画刷
painter.setBrush(brush);
// 绘制圆
painter.drawEllipse(QPoint(300, 300), 100, 100);
}
实现效果如下:
3. 绘制图片
Qt 提供了四个类来处理图像数据:QImage、QPixmap、QBitmap 和 QPicture,它们都是常用的绘图设备。其中QImage主要用来进行 I/O 处理,它对 I/O 处理操作进行了优化,而且可以用来直接访问和操作像素;QPixmap 主要用来在屏幕上显示图像,它对在屏幕上显示图像进行了优化;QBitmap 是 QPixmap 的子类,用来处理颜色深度为1的图像,即只能显示黑白两种颜色;QPicture 用来记录并重演 QPainter 命令。
3.1 绘制简单图片
1. 新建 Qt 项目,基类选择 QWidget,项目名称为 QPainter。在 "widget.h" 头文件中声明绘画事件;如下图示:
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
// 声明绘画事件
void paintEvent(QPaintEvent *event);
private:
Ui::Widget *ui;
};
2. 创建 resource.qrc,并导入图片
3. 在 "widget.cpp" 文件中实现画图片功能;
void Widget::paintEvent(QPaintEvent *event)
{
// 实例化画家对象
(void)event;
QPainter painter(this);
// 画图片
painter.drawPixmap(0, 0, QPixmap(":/fengche.jpg"));
}
实现效果如下:
3.2 平移图片
平移图片实际是通过改变坐标来实现。QPainter类中提供了 translate()函数 来实现坐标原点的改变。
示例:
void Widget::paintEvent(QPaintEvent *event)
{
// 实例化画家对象
(void)event;
QPainter painter(this);
// 平移图片
painter.translate(100, 100);
// 画图片
painter.drawPixmap(0, 0, QPixmap(":/fengche.jpg"));
}
实现效果如下:
3.3 缩放图片
在 Qt 中,图片的放大和缩小可以使用 QPainter类 中的 drawPixmap()函数 来实现。
示例:
void Widget::paintEvent(QPaintEvent *event)
{
// 实例化画家对象
(void)event;
QPainter painter(this);
QPixmap pixmap(":/fengche.jpg");
// 缩放图片
// 以(100,100)点开始画图,图片尺寸变为:400 * 300
painter.drawPixmap(100, 100, 400, 300, pixmap);
}
实现效果如下:
3.4 旋转图片
图片的旋转使用的是 QPainter类 中的 rotate()函数,它默认是以原点为中心进行旋转的。如果要改变旋转的中心,可以使用 translate()函数 完成。
示例:
void Widget::paintEvent(QPaintEvent *event)
{
// 实例化画家对象
(void)event;
QPainter painter(this);
QPixmap pixmap(":/fengche.jpg");
// 顺时针旋转 180 度
painter.rotate(180);
painter.translate(-800, -600);
painter.drawPixmap(100, 100, 400, 300, pixmap);
}
实现效果如下: