文章目录
- 一、基本绘图技术介绍
- 二、常见的18种图形、路径、文字、图片绘制
- 三、Qt移动鼠标绘制任意形状
- 四、Qt绘制带三角形箭头的窗口
一、基本绘图技术介绍
Qt提供了绘图技术,程序员可以在界面上拖动鼠标,或者在代码里指定参数进行绘图。
Qt绘图技术介绍:
-
QPainter
基本要素
-
QPen:用于控制线条的颜色、宽度、线型等;
-
宽度(Width):
- 通过
setWidth()
方法设置画笔的宽度,这将决定绘制线条的粗细。
- 通过
-
颜色(Color):
- 使用
setColor()
方法设置画笔的颜色。颜色可以是Qt
命名的颜色常量,如Qt::red
,或者使用QColor
对象定义的更具体的颜色。
- 使用
-
样式(Style):
-
setStyle()
方法定义了线条的样式。可以是实线(Qt::SolidLine
)、虚线(Qt::DashLine
)、点线(Qt::DotLine
)等。
-
-
端点样式(Cap Style):
-
setCapStyle()
方法设置线条端点的样式。常见的端点样式有方形(Qt::SquareCap
)、圆形(Qt::RoundCap
)和平面(Qt::FlatCap
)。
-
-
连接样式(Join Style):
-
setJoinStyle()
方法定义了线条连接处的样式。斜接(Qt::MiterJoin
)是默认样式,适用于大多数情况。还可以选择圆角(Qt::RoundJoin
)或斜切(Qt::BevelJoin
)。
-
-
线型(Dash Pattern):
- 对于虚线或点线,可以通过
setDashPattern()
方法设置具体的虚线模式,例如定义点和间隔的长度。
- 对于虚线或点线,可以通过
-
笔刷(Brush):
- 虽然
QPen
主要用于线条,但它也有一个setBrush()
方法,可以设置用于填充形状轮廓的画刷样式。
- 虽然
-
使用
QPen
:- 创建
QPen
对象后,可以通过上述方法设置其属性,然后通过QPainter::setPen()
方法将其应用到QPainter
对象上。之后,QPainter
将使用这个画笔的样式来绘制线条和形状的轮廓。
- 创建
示例:
QPainter painter; Qpen pen; //设置画笔属性 pen.setWidth(10); //设置画笔的宽度为10像素。 pen.setColor(Qt::red); //设置画笔的颜色为红色 pen.setStyle(Qt::SolidLine); //设置画笔的样式为实线 pen.setCapStyle(Qt::SquareCap); //设置画笔端点的样式为方形 pen.setJoinStyle(Qt::MiterJoin); // 设置画笔线条连接处的样式为斜接,这是最常用的线条连接方式,适用于大多数情况。 painter.setPen(pen); //将设置好的QPen对象应用到QPainter对象上
-
宽度(Width):
-
QBrush:设置区域填充特性,可以设置填充颜色、填充方式、渐变特性等,还可以采用图片做纹理填充
-
颜色设置:
-
QBrush
可以通过setColor()
方法设置填充颜色。颜色可以使用QColor
对象指定,提供广泛的颜色选择。
-
-
填充样式:
-
setStyle()
方法用于设置填充样式。Qt::BrushStyle
枚举提供了多种预定义的填充样式,如:-
Qt::SolidPattern
:纯色填充。 -
Qt::HorizontalPattern
和Qt::VerticalPattern
:水平或垂直条纹填充。 -
Qt::CrossPattern
和Qt::BDiagPattern
:交叉或对角线条纹填充。 -
Qt::DenseNPattern
:提供不同密度的条纹或点状图案。
-
-
-
渐变填充:
-
QBrush
支持使用渐变作为填充模式。可以创建QLinearGradient
或QRadialGradient
对象,并将其设置为QBrush
的渐变属性。
-
-
纹理填充:
- 通过
setTexture()
方法,可以将QPixmap
或QImage
对象设置为纹理,用于填充形状。
- 通过
-
透明度:
-
setOpacity()
方法允许设置填充的透明度,范围从 0(完全透明)到 1(完全不透明)。
-
-
变换:
-
setTransform()
方法可以对QBrush
应用变换,如旋转、缩放等,这会影响纹理或渐变在形状上的呈现方式。
-
-
使用
QBrush
:- 在绘制过程中,一旦
QBrush
对象被设置好,就可以通过QPainter::setBrush()
方法将其应用到QPainter
对象上。随后,使用QPainter
绘制的封闭形状将使用该画刷进行填充。
- 在绘制过程中,一旦
示例:
QPainter painter; QBrush brush; brush.setColor(Qt::yellow); // 设置为黄色 brush.setStyle(Qt::SolidPattern); //设置填充样式为纯色填充 painter.setBrush(brush);
-
颜色设置:
-
QFont:绘制文字时,设置文字的字体样式、大小等属性
-
字体名称(Family):
- 使用
setFamily()
方法设置字体的名称,如 “Arial”、“Times New Roman” 等。
- 使用
-
字体大小(Size):
-
setPointSize()
方法用于设置字体的大小,通常以点为单位。
-
-
字体风格(Style):
-
setStyle()
方法可以设置字体的风格,如QFont::StyleNormal
、QFont::StyleItalic
等。
-
-
字体粗细(Weight):
- 使用
setWeight()
方法设置字体的粗细,如QFont::Light
、QFont::Normal
、QFont::Bold
。
- 使用
-
字体拉伸(Stretch):
-
setStretch()
方法用于设置字体的宽度拉伸,可以使得字体更宽或更窄。
-
-
字体间距(Kerning):
-
setKerning()
方法可以启用或禁用字符间距调整,影响字符之间的空间。
-
-
字体字距(Letter Spacing):
-
setLetterSpacing()
方法设置字符之间的水平间距。
-
-
文本方向(Text Direction):
-
setStyleStrategy()
方法可以设置文本的方向,如从左到右或从右到左。
-
-
固定宽度字体(Fixed Pitch):
-
setFixedPitch()
方法用于设置是否使用固定宽度字体。
-
-
使用
QFont
:- 创建
QFont
对象后,可以通过上述方法设置其属性,然后通过QPainter::setFont()
方法将其应用到QPainter
对象上。之后,使用QPainter
绘制的文本将使用这个字体。
- 创建
示例:
QFont font; font.setFamily("Helvetica"); font.setPointSize(12); font.setBold(true); // 设置为粗体 font.setStyleItalic(true); // 设置为斜体 QPainter painter; painter.setFont(font); painter.drawText(10, 20, "Hello, World!"); // 使用字体绘制文本
-
字体名称(Family):
-
渐变填充
-
QLinearGradient:线性渐变填充,颜色沿着直线从一点渐变到另一点。可以指定起点和终点,以及中间的颜色停止点来创建平滑的颜色过渡。
-
起点和终点:
-
QLinearGradient
需要两个点来定义渐变的方向和范围:起始点和终点。渐变的颜色将从起始点开始,向终点过渡。
-
-
颜色停止:
- 使用
setColorAt()
方法可以设置颜色在渐变中的停止点。这个方法接受一个0到1之间的值,表示从起始点到终点的相对位置,以及一个QColor
对象,表示该位置的颜色。
- 使用
-
渐变坐标系统:
- 渐变的坐标系统可以是对象坐标系或绝对坐标系。通过
setCoordinateMode()
方法可以设置渐变的坐标模式。
- 渐变的坐标系统可以是对象坐标系或绝对坐标系。通过
-
坐标模式:
-
QLinearGradient
支持两种坐标模式:-
ObjectBoundingMode
:渐变是相对于使用渐变的对象的边界框。 -
StretchToDeviceMode
:渐变是相对于整个设备(如画布或窗口)的尺寸。
-
-
-
使用
QLinearGradient
:- 创建
QLinearGradient
对象后,设置起始点、终点和颜色停止点,然后将它作为QBrush
对象的样式来使用。
- 创建
示例:
QLinearGradient gradient(0, 0, 100, 100); // 定义从左到右的渐变 gradient.setColorAt(0.0, QColor("red")); // 起始颜色为红色 gradient.setColorAt(1.0, QColor("blue")); // 结束颜色为蓝色 QBrush brush(gradient); // 创建一个使用渐变的画刷 QPainter painter; painter.setBrush(brush); painter.drawRect(10, 10, 100, 100); // 使用画刷填充矩形
-
起点和终点:
-
QRadialGradient:径向渐变填充,颜色从中心点向外辐射,形成一个圆形或椭圆形的渐变效果。这种渐变通常用于创建按钮或图标的立体感。
-
QConicalGradient:圆锥形渐变填充,颜色从一个点向外辐射,但与径向渐变不同,圆锥形渐变的颜色过渡是沿着圆锥的侧面进行的,而不是沿着半径。这种渐变较少使用,但可以创造出独特的视觉效果。
-
-
-
QPaintDevice
是一个可以使用QPainter进行绘图的抽象的二维界面
常用的绘图设备:
- QWidget
- QPixmap、QImage:可用来绘制视频图片数据
-
QPaintEngine
- 给QPainter提供在不同设备上绘图的接口
- 应用程序一般无需与QPaintEngine打交道
- 可以禁用QPaintEngine,使用DX或OPenGL自渲染
-
绘图事件paintEvent()
绘图事件,需要用户override
-
坐标系:原点在左上角,x向左为正,y向下为正
-
基本的绘图元素
在Qt框架中,这些操作是通过
QPainter
类实现的。QPainter
是一个低级的绘图类,提供了丰富的方法来绘制线条、形状、文本和图像。使用QPainter
时,你通常会先创建一个QPainter
对象,然后设置画笔、画刷等属性,最后调用相应的绘图函数来绘制内容。- 点
-
drawPoint
: 用于绘制单个点。 -
drawPoints
: 用于绘制多个点。通常需要一个点的数组或列表作为参数。
-
- 线
- 直线:
drawLine
用于绘制直线。通常需要两个点(起点和终点)作为参数。 - 圆弧:
drawArc
用于绘制圆或椭圆的一部分,即圆弧。需要指定圆心、半径、起始角度和结束角度。
- 直线:
- 封闭的图形
- 矩形
- 普通矩形:
drawRect
: 用于绘制一个矩形的边框或填充整个矩形。 - 圆角矩形:
drawRoundedRect
: 用于绘制带有圆角的矩形。
- 普通矩形:
- 弧弦:
drawChord
用于绘制一个圆弧以及与圆弧两端点相连的直线,形成一个封闭的图形 - 椭圆:
drawEllipse
用于绘制椭圆的边框或填充整个椭圆
- 矩形
- 任意路径绘制
- drawPolygon:绘制一个多边形。传入的点列表中最后一个点会自动与第一个点相连,形成一个闭合的多边形。
- drawPolyline:与
drawPolygon
类似,drawPolyline
用于绘制一系列点连接成的折线,但最后一个点不会与第一个点相连,因此结果是开放的。 - drawConvexPolygon:用于绘制任意凸多边形。凸多边形是指任意两个顶点之间的线段都不会与其他顶点相交的多边形。
- drawLines:绘制一系列的线段。你需要传入一系列的起点和终点来定义这些线段。
- drawPath:用于绘制更复杂的路径,可以包含直线段、曲线段等
- drawPie:用于绘制扇形,即圆的一部分。你需要指定圆心、半径、起始角度和结束角度来定义扇形。
- 图片绘制
-
drawPixmap
: 用于在指定位置绘制QPixmap
对象,QPixmap
是Qt中用于存储图像数据的类。 -
drawImage
: 类似于drawPixmap
,但用于绘制QImage
对象,QImage
是另一个图像类,通常用于处理像素数据。
-
- 绘制文本
-
drawText
: 用于在指定位置绘制文本。你可以指定文本内容、位置、对齐方式等属性。
-
- 其他操作
-
eraseRect
: 用于擦除指定矩形区域内的内容,通常是用当前画笔的背景色来填充这个区域。 -
fillPath
: 用于填充由QPainterPath
定义的路径。如果设置了画笔颜色,路径内部会被填充,但不会绘制路径的轮廓线。 -
fillRect
: 用于填充一个矩形区域,如果设置了画笔样式,矩形的边框也会被绘制。
-
- 点
二、常见的18种图形、路径、文字、图片绘制
利用QTreeView类的信号void clicked(const QModelIndex &index);
得到要绘制的图形,触发槽函数,槽函数用于设置绘图样式并调用update()
函数触发paintEvent()
绘图事件函数,在该函数中绘制已选择的图形。
示例:
drawtype.h
:
#pragma once
//基本画图枚举
enum class DRAW_TYPE
{
point,
multipoints,
line,
arc,
rect,
roundrect,
chord,
ellipse,
polygon,
polyline,
ConvexPloygon,
lines,
path,
pie,
image,
pixmap,
draw_text,
draw_erase,
draw_fillpath,
draw_fillrect
};
CPaintWidget.h
:
#pragma once
#include <QWidget>
#include "drawtype.h"
class CPaintWidget : public QWidget
{
Q_OBJECT
public:
CPaintWidget(QWidget* p = nullptr);
~CPaintWidget() {}
void setDrawType(DRAW_TYPE type); //设置绘图类型
private:
void paintEvent(QPaintEvent* event) override; //绘图事件
private:
/* 绘制基本图形 */
void draw_point();
void draw_multipoints();
void draw_line();
void draw_arc();
void draw_rect();
void draw_roundrect();
void draw_chord();
void draw_ellipse();
void draw_polygon();
void draw_polyline();
void draw_ConvexPloygon();
void draw_lines();
void draw_path();
void draw_pie();
void draw_image();
void draw_pixmap();
void draw_text();
void draw_erase();
void draw_fillpath();
void draw_fillrect();
private:
DRAW_TYPE m_drawType;
int W = 0;
int H = 0;
};
CPaintWidget.cpp
:
#include "CPaintWidget.h"
#include <QPainter>
#include <QPainterPath>
CPaintWidget::CPaintWidget(QWidget* p)
:QWidget(p)
{
this->setMinimumSize(800, 600);
m_drawType = DRAW_TYPE::polygon;
}
void CPaintWidget::paintEvent(QPaintEvent* event)
{
W = this->width();
H = this->height();
switch (m_drawType)
{
case DRAW_TYPE::point:
draw_point();
break;
case DRAW_TYPE::multipoints:
draw_multipoints();
break;
case DRAW_TYPE::line:
draw_line();
break;
case DRAW_TYPE::arc:
draw_arc();
break;
case DRAW_TYPE::rect:
draw_rect();
break;
case DRAW_TYPE::roundrect:
draw_roundrect();
break;
case DRAW_TYPE::chord:
draw_chord();
break;
case DRAW_TYPE::ellipse:
draw_ellipse();
break;
case DRAW_TYPE::polygon:
draw_polygon();
break;
case DRAW_TYPE::polyline:
draw_polyline();
break;
case DRAW_TYPE::ConvexPloygon:
draw_ConvexPloygon();
break;
case DRAW_TYPE::lines:
draw_lines();
break;
case DRAW_TYPE::path:
draw_path();
break;
case DRAW_TYPE::pie:
draw_pie();
break;
case DRAW_TYPE::image:
draw_image();
break;
case DRAW_TYPE::pixmap:
draw_pixmap();
break;
case DRAW_TYPE::draw_text:
draw_text();
break;
case DRAW_TYPE::draw_erase:
draw_erase();
break;
case DRAW_TYPE::draw_fillpath:
draw_fillpath();
break;
case DRAW_TYPE::draw_fillrect:
draw_fillrect();
break;
default:
break;
}
}
void CPaintWidget::draw_point()
{
QPainter painter(this);
QPen pen;
pen.setWidth(10);
pen.setColor(Qt::red);
pen.setStyle(Qt::SolidLine);
painter.setPen(pen);
painter.drawPoint(QPoint(W / 2, H / 2));
}
void CPaintWidget::draw_multipoints()
{
QPainter painter(this);
QPen pen;
pen.setWidth(10);
pen.setColor(Qt::blue);
pen.setStyle(Qt::SolidLine);
painter.setPen(pen);
// 画很多点
QPoint points[] = {
QPoint(5 * W / 12,H / 4),
QPoint(3 * W / 4, 5 * H / 12),
QPoint(2 * W / 4, 5 * H / 12) };
painter.drawPoints(points, 3);
}
void CPaintWidget::draw_line()
{
QPainter painter(this);
//QLine Line(W / 4, H / 4, W / 2, H / 2);
QLine Line(W / 4, H / 4, W / 2, H / 4);
painter.drawLine(Line);
}
void CPaintWidget::draw_arc()
{
QPainter painter(this);
QRect rect(W / 4, H / 4, W / 2, H / 2);
int startAngle = 90 * 16;
int spanAngle = 90 * 16; //旋转 90°
painter.drawArc(rect, startAngle, spanAngle);
}
void CPaintWidget::draw_rect()
{
QPainter painter(this);
// 画矩形
QRect rect(W / 4, H / 4, W / 2, H / 2);
painter.drawRect(rect);
}
void CPaintWidget::draw_roundrect()
{
QPainter painter(this);
// 画圆角矩形
QRect rect(W / 4, H / 4, W / 2, H / 2);
painter.drawRoundedRect(rect, 20, 20);
}
void CPaintWidget::draw_chord()
{
QPainter painter(this);
QRect rect(W / 4, H / 4, W / 2, H / 2);
int startAngle = 90 * 16;
int spanAngle = 90 * 16;
painter.drawChord(rect, startAngle, spanAngle);
}
void CPaintWidget::draw_ellipse()
{
QPainter painter(this);
QRect rect(W / 4, H / 4, W / 2, H / 2);
painter.drawEllipse(rect);
}
void CPaintWidget::draw_polygon()
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPen pen;
pen.setWidth(10);
pen.setColor(Qt::red);
pen.setStyle(Qt::SolidLine);
pen.setCapStyle(Qt::SquareCap);
pen.setJoinStyle(Qt::MiterJoin); //画笔断点的样式
painter.setPen(pen);
QBrush brush;
brush.setColor(Qt::yellow);
brush.setStyle(Qt::SolidPattern);
painter.setBrush(brush);
// 画多边形,最后一个点会和第一个点闭合
QPoint points[] = {
QPoint(5 * W / 12,H / 4),
QPoint(3 * W / 4,5 * H / 12),
QPoint(5 * W / 12,3 * H / 4),
QPoint(2 * W / 4,5 * H / 12) };
painter.drawPolygon(points, 4);
}
void CPaintWidget::draw_polyline()
{
QPainter painter(this);
// 画多点连接的线,最后一个点不会和第一个点连接
QPoint points[] = {
QPoint(5 * W / 12, H / 4),
QPoint(3 * W / 4