2D绘图简介
为什么要2D绘图
在Qt界面编程中,通常会遇到使用Qt自带控件不能解决的问题,这时2D绘图给我们提 供了专用定制化的工具
QPainter介绍
2D绘图离不开QPainter,可以把QPainter想象成一个画笔,开发人员拿着画笔理论上 是可以绘制任何你想要的图形。QPainter 一般在一个部件(widget)重绘事件( PaintEvent )的处理函数paintEvent ()中进行绘制,首先要创建QPainter 对象(画 笔),然后进行图形的绘制
QPainter中常用的图形绘制函数
- drawArc() 弧
- drawChord()弦
- drawConvexPolygon() 凸多边形
- drawEllipse() 椭圆,注意椭圆是先整个框,然后逼近…
- drawImage() 图像
- drawLine() 线
- drawLines() 多条线
- drawPath() 路径; 想到哪就去哪,但是必须是直的
- drawPicture() 按QPainter指令绘制 区分drawImage、drawPixmap,大家可以试一把
- drawPie() 扇形
- drawPixmap() 图像
- drawPoint() 点
- drawPoints() 多个点
- drawPolygon() 多边形
- drawPolyline() 多折线
- drawRect() 矩形
- drawRects() 多个矩形
- drawRoundRect() 圆角矩形
- drawText() 文字
- drawTiledPixmap() 平铺图像
- drawLineSegments() 绘制折线
画笔(QPen)与画刷(QBrush)
QPen
QPen定义了用于QPainter应该怎样画线或者轮廓线。画笔具有样式style() 、宽 度width() 、画刷brush() 、笔帽样式capStyle()和连接样式joinStyle()等属性。画笔的样式style()定义了线的样式。画刷brush()用于填充画笔所绘制的线条。笔帽 样式capStyle()定义了使用QPainter绘制的线的末端;连接样式joinStyle()则定义 了两条线如何连接起来。画笔宽度width()或widthF()定义了画笔的宽。注意,不 存在宽度为 0 的线。假设你设置 width 为 0,QPainter依然会绘制出一条线,而 这个线的宽度为 1 像素。也就是说,画笔宽度通常至少是 1 像素。
QBrush
QBrush 类提供了画刷来对图形进行填充, 一个画刷具有样式(style)、颜色 (color)、渐变( gradient )、文理(texture)四个可设置属性。 可能用到Brush的样式、颜色、填充方式 (后两者是重点) const QColor &QBrush::color() const 获取当前Brush颜色 void QBrush::setColor(const QColor &color) 设置当前Brush颜色
渐变( gradient )定义了渐变填充。当创建Qbrush时,可以在构造函数中传入一个渐变 画笔对象用于构建画刷的渐变样式
paintEvent调用时机
什么时候paintEvent时间会产生?
- 窗口隐藏 显示 show
- 窗口放大 缩小 resize
- 调用update
- 调用repaint
坐标系及窗口移动原理
三个坐标系的关系
- windowDeskTopLeft 是指窗口到显示器左上角的坐标
windowDeskTopLeft = this‐>geometry().topLeft()
- mouseDeskTopLeft 是指鼠标(光标)到显示器左上角的坐标
mouseDeskTopLeft = event‐>globalPos();
- mouseWindowTopLeft 是指鼠标(光标)到窗口左上角的坐标
mouseWindowTopLeft = event‐>pos();
它们三者的关系是(矢量相减):
windowDeskTopLeft = mouseDeskTopLeft mouseWindowTopLeft;
窗口移动的坐标系关系
- step1 记录鼠标左键按下时的mouseWindowTopLeft (响应mousePressEvent事件)
- step2 鼠标移动时实时记录mouseWindowTopLeft (实时响应mouseMoveEvent事件, 需要setMouseTracking(true))
- step3 在mouseMoveEvent中实时算出windowDeskTopLeft,并将窗口移动到该位置
通过公式 windowDeskTopLeft = mouseDeskTopLeft mouseWindowTopLeft; 计 算而来。 PS:在 中需要使用if (event>buttons() & Qt::LeftButton)对左键进行过滤,不然鼠 标移动到哪里,不用按下左键窗口都会跟着走
QPainter中scale
- scale参数 (同比例缩放)
scale(qreal sx, qreal sy)
sx = x方向scale的倍数
sy = y方向scale的倍数
QPainter中的save 和 restore
在2D绘制中经常遇到画笔坐标轴移动 画笔换色等等操作,在切换另一种操作前,需要 先save一次,完成后再restore一次。
QPainter 2D绘制基础实例
绘制文字
void Widget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
painter.begin(this);
painter.setPen(QColor(255, 10, 10)); //设置颜色
font.setFamily("Microsoft YaHei");
font.setPointSize(66); //字体大小
font.setItalic(true); //斜体
painter.setFont(font); //使字体生效
painter.drawText(rect(), Qt::AlignCenter, "Hello Man!");
painter.end();
}
绘制直线
void Widget::paintEvent(QPaintEvent *event)
{ // 绘制直线
Q_UNUSED(event);
painter.begin(this);
painter.setPen(QColor(255, 10, 10)); //设置颜色
painter.setPen(QPen(QColor(255,10,10), 9)); //可以设置线宽度
painter.setRenderHint(QPainter::Antialiasing, true); //设置 反锯齿
painter.drawLine(QPointF(0, this->height()), //画直线
QPointF(this->width() / 2,
this->height() / 2)); //QPointF 装起点坐标 终点坐标
painter.end();
}
绘制矩形
void Widget::paintEvent(QPaintEvent *event)
{ // 绘制矩形
Q_UNUSED(event);
painter.begin(this);
//设置 反锯齿
painter.setRenderHint(QPainter::Antialiasing, true);
//设置笔的颜色、宽度
painter.setPen(QPen(QColor(0, 160, 230), 9));
//设置笔刷颜色
// painter.setBrush(QColor(255, 160, 90));
//画直线
painter.drawRect(50, 50, 100, 100);
painter.end();
}
绘制弧形
首先需要有个位置矩形,何为“位置矩形”,就是用来装这个弧的
void Widget::paintEvent(QPaintEvent *event)
{ // 绘制弧形
Q_UNUSED(event);
// 矩形
QRectF rect(90.0,90.0,80.0,90.0);
int startAngle = 30*16;
// 跨度系数
int spanAngle = 120 * 16;
painter.begin(this);
//设置 反锯齿
painter.setRenderHint(QPainter::Antialiasing, true);
//设置笔的颜色、宽度
painter.setPen(QPen(QColor(0, 160, 230), 9));
//设置笔刷颜色
// painter.setBrush(QColor(255, 160, 90));
//drawArc 三个参数:起始角度、跨度、位置矩阵
// 注意角度被分成了十六分之 一,就是说,如果要 30 度,就需是 30*16
// 正数角度表示逆时针方向,负数表示顺时针方向,0表示正三点位置
painter.drawArc(rect,startAngle,spanAngle);
painter.end();
}
绘制椭圆
基本知识:椭圆也是框在矩形里面
void Widget::paintEvent(QPaintEvent *event)
{ // 绘制字体
Q_UNUSED(event);
painter.begin(this);
// 设置反锯齿
painter.setRenderHint(QPainter::Antialiasing,true);
// 设置笔的颜色宽度
painter.setPen(QPen(QColor(0,0,0),4));
QRectF rect(10.0,20.0,80.0,60.0);
painter.drawEllipse(rect); // 画圆
// X轴Y轴 宽 高
QRectF rect_2(60.0,80.0,100.0,100.0);
painter.drawRect(rect_2); // 画矩形
painter.drawEllipse(rect_2); // 画圆
painter.end();
}
绘制多边形
void Widget::paintEvent(QPaintEvent *event)
{
// 绘制多边形
static const QPointF point[4] ={
QPointF(10.0,80.0),
QPointF(20.0,10.0),
QPointF(80.0,30.0),
QPointF(90.0,70.0)
};
// 代替了上面的begin 和 end
QPainter paint(this);
paint.drawConvexPolygon(point,4);
}
绘制路径
经典的贝塞尔曲线
void Widget::paintEvent(QPaintEvent *event)
{
// 绘制路径
QPainterPath path;
path.addRect(20,20,60,60); // 添加矩形
path.moveTo(0,0); // 设置起点
path.cubicTo(99,0,50,50,99,99); // 绘制上贝塞尔曲线
path.cubicTo(0,99,50,50,0,0); // 绘制下贝塞尔曲线
// 两种不同的填充模式,一个是全部填充 一个是去除重复
path.setFillRule(Qt::OddEvenFill);
painter.begin(this);
painter.fillRect(0,0,100,100,Qt::white); // 填充矩形
painter.setPen(QPen(QColor(43,65,89),5,Qt::SolidLine,Qt::FlatCap
,Qt::MiterJoin));// 设置画笔
painter.setBrush(QColor(122,163,34)); // 设置笔刷颜色
painter.drawPath(path);
painter.end();
}
绘图的三种方式
- drawImage
- drawPixmap
- drawPicture
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter;
// 绘制image
QImage image(100, 100, QImage::Format_ARGB32);
painter.begin(&image);
painter.setPen(QPen(Qt::green, 3));
painter.setBrush(Qt::yellow);
painter.drawRect(10, 10, 60, 60);
painter.drawText(10, 10, 60, 60, Qt::AlignCenter, tr("QImage"));
painter.setBrush(QColor(0 , 0, 0, 100));
painter.drawRect(50, 50, 40, 40);
painter.end();
// 绘制pixmap
QPixmap pix(100, 100);
painter.begin(&pix);
painter.setPen(QPen(Qt::green, 3));
painter.setBrush(Qt::yellow);
painter.drawRect(10, 10, 60, 60);
painter.drawText(10, 10, 60, 60, Qt::AlignCenter, tr("QPixmap"));
painter.setBrush(QColor(0 , 0, 0, 100));
painter.drawRect(50, 50, 40, 40);
painter.end();
// 绘制bitmap
QBitmap bit(100, 100);
painter.begin(&bit);
painter.setPen(QPen(Qt::green, 3));
painter.setBrush(Qt::yellow);
painter.drawRect(10, 10, 60, 60);
painter.drawText(10, 10, 60, 60, Qt::AlignCenter, tr("QBitmap"));
painter.setBrush(QColor(0 , 0, 0, 100));
painter.drawRect(50, 50, 40, 40);
painter.end();
// 绘制picture
QPicture picture;
painter.begin(&picture);
painter.setPen(QPen(Qt::green, 3));
painter.setBrush(Qt::yellow);
painter.drawRect(10, 10, 60, 60);
painter.drawText(10, 10, 60, 60, Qt::AlignCenter, tr("QPicture"));
painter.setBrush(QColor(0 , 0, 0, 100));
painter.drawRect(50, 50, 40, 40);
painter.end();
// 在widget部件上进行绘制
painter.begin(this);
painter.drawImage(50, 20, image);
painter.drawPixmap(200, 20, pix);
painter.drawPixmap(50, 170, bit);
painter.drawPicture(200, 170, picture);
}
抗锯齿(反走样)
抗锯齿( Antialiased)又称为反锯齿或者反走样,就是对图像的边缘进行平滑处 理,使其看起来更加柔和流畅的一种技术。QPaint er 进行绘制时可以使用QPainter ::RenderHint 渲染提示来指定是否要使用抗锯齿功能,RenderHint 取值分为以下三
种。
常量 | 描述 |
---|---|
QPainter::Antialiasing | 边缘抗锯齿 |
QPainter::TextAntialiasing | 文字抗锯齿 |
QPainter::SmoothPixmapTransform | 平滑pixmap转换算法抗锯齿 |
ps :绘制直线演示了 Antialiasing 绘制文字可以使用 TextAntialiasing 转盘演示了 SmoothPixmapTransform