1.1 为什么需要2D绘图
在Qt界面编程中,通常会遇到使用Qt自带控件不能解决的问题,这时2D绘图给我们提 供了专用定制化的工具。
1.2 QPainter介绍
2D绘图离不开QPainter,可以把QPainter想象成一个画笔,开发人员拿着画笔理论上 是可以绘制任何你想要的图形。QPainter 一般在一个部件(widget)重绘事件( PaintEvent )的处理函数paintEvent ()中进行绘制,首先要创建QPainter 对象(画 笔),然后进行图形的绘制。
1.3 QPainter中常用的图形绘制函数
drawArc() 弧
drawChord() 弦
drawConvexPolygon() 凸多边形
drawEllipse() 椭圆,注意椭圆是先整个框,然后逼近…
drawImage() 图像
drawLine() 线
drawLines() 多条线
drawPath() 路径; 想到哪就去哪,但是必须是直的
drawPicture() 按QPainter指令绘制 区分drawImage、drawPixmap,大家可以试一把
drawPie() 扇形
drawPixmap() 图像 1.8给出了例子 image pixmap piture
drawPoint() 点
drawPoints() 多个点
drawPolygon() 多边形
drawPolyline() 多折线
drawRect() 矩形
drawRects() 多个矩形
drawRoundRect() 圆角矩形
drawText() 文字
drawTiledPixmap() 平铺图像
drawLineSegments() 绘制折线
1.4 画笔(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时,可以在构造函数中传入一个渐变 画笔对象用于构建画刷的渐变样式
1.5 探讨paintEvent什么时候调用
什么时候 paintEvent事件会产生
1 窗口隐藏>显示 show
2 窗口缩小或者放大 resize
3 调用update()
4 调用repaint()
1.6 再谈坐标系及窗口移动原理
1.6.1 三个坐标的关系
windowDeskTopLeft 是指窗口到显示器左上角的坐标;
windowDeskTopLeft = this‐>geometry().topLeft()
注意:这里的this就是Widget对象,所以不包括应用程序的标题栏
mouseDeskTopLeft 是指鼠标(光标)到显示器左上角的坐标;
mouseDeskTopLeft = event‐>globalPos();
mouseWindowTopLeft 是指鼠标(光标)到窗口左上角的坐标;
mouseWindowTopLeft = event‐>pos();
它们三者的关系是(矢量相减):
windowDeskTopLeft = mouseDeskTopLeft mouseWindowTopLeft;
1.6.2 窗口移动的坐标关系
step1 记录鼠标左键按下时的mouseWindowTopLeft (响应mousePressEvent事件)
step2
鼠标移动时实时记录mouseWindowTopLeft (实时响应mouseMoveEvent事件, 需要setMouseTracking(true))
通过公式 windowDeskTopLeft = mouseDeskTopLeft mouseWindowTopLeft; 计 算而来。
PS:在 中需要使用if (event>buttons() & Qt::LeftButton)对左键进行过滤,不然鼠
标移动到哪里,不用按下左键窗口都会跟着走。
1.7 QPainter中scale
scale:同比例缩放
The most commonly used transformations are scaling, rotation, translation and shearing. Use the scale() function to scale the coordinate system by a given offset, the rotate() function to rotate it clockwise and translate() to translate it (i.e. adding a given offset to the points). You can also twist the coordinate system around the origin using the shear() function. See the Affine Transformations example for a visualization of a sheared coordinate system.
scale参数
scale(qreal sx, qreal sy) sx = x方向scale的倍数 sy = y方向scale的倍数
1.8 QPainter中的save 和 restore
在2D绘制中经常遇到画笔坐标轴移动 画笔换色等等操作,在切换另一种操作前,需要
先save一次,完成后再restore一次。
2.1 绘制文字
Q_UNUSED(event);//没有实质性的作用用来避免编译器警告
void Widget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);//没有实质性的作用用来避免编译器警告
QPainter painter;
QFont Font;
painter.begin(this);
painter.setPen(QColor(255,10,10));
Font.setPointSize(66);//设置字体大小
Font.setItalic(true);//斜体
painter.setFont(Font);//使字体生效
painter.drawText(rect(),Qt::AlignCenter,"Hello TZ EDU!");
painter.end();
}
Q_UNUSED(this);
QPainter painter;
painter.begin(this);
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();
Q_UNUSED(this);
QPainter painter;
//设置反锯齿
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();
Q_UNUSED(event);
QRectF rect(90.0,90.0,80.0,90.0);
int startAngle=30*16;
//跨越度数
int spanAngle=120*16;
QPainter painter;
painter.begin(this);
//设置反锯齿
painter.setRenderHint(QPainter::Antialiasing,true);
painter.setPen(QPen(QColor(0,160,230),2));
//painter.drawRect(rect);画矩形
//画弧
//drawArc需要三个参数:起始角度、跨度、位置矩阵;
painter.drawArc(rect,startAngle,spanAngle);
painter.end();
这里需要了解弧度的基本知识
drawArc需要三个参数:起始角度、跨度、位置矩阵;注意角度被分成了十六分之 一,就是说,如果要 30 度,就需是 30*16。
2.5 绘制椭圆
//椭圆也是在矩形里面
Q_UNUSED(this);
QPainter painter;
painter.begin(this);
//设置反锯齿
painter.setRenderHint(QPainter::Antialiasing,true);
painter.setPen(QPen(QColor(0,160,230),2));
QRectF rectangle2(10.0,20.0,80.0,60.0);
painter.drawRect(rectangle2);
painter.drawEllipse(rectangle2);
painter.end();
Q_UNUSED(this);
//这里用 QPainter painter(this); 代替了上面的begin 和 end
QPainter painter(this);
static const QPoint points[4]={QPoint(10.0,80.0),
QPoint(20.0,10.0),
QPoint(80.0,30.0),
QPoint(90.0,70.0)};
painter.drawConvexPolygon(points,4);
//经典的贝塞尔曲线
QPainter painter(this);
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.fillRect(0,0,100,100,Qt::white);//填充矩形
painter.setPen(QPen(QColor(122,163,39)));//设置画笔
painter.setBrush(QColor(122,163,39));//设置画刷颜色
painter.drawPath(path);//绘制路径
QPainter painter;
//绘制image
QImage image(100,100,QImage::Format_ARGB32);//大小100*100
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);//大小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("QBitmap"));
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);//左端起点(200,20)
painter.drawPixmap(50,170,bit);
painter.drawPicture(200, 170, picture);
这三种绘图方式都是QPaintDevice的子类
QImage
依赖软件,直接像素访问,适合大图片
既然依赖软件,那么就不需要用硬件GUI的线程了,可以开个软件的线程,可提高用户UI体验
QPixmap
(依赖硬件,加速显示,适合小图片)
QPixmap的设计本来就是用来加速显示,用paint绘图时用QPixmap会比其他类的效果好很多。
一般小图片用QPixmap。
QBitmap是QPixmap的一个子类,主要用于显示单色位图
当图片较大时,可以用QImage先把图片加载进来—调整大小—转成QPixmap输出
QPicture
保存绘图的状态(二进制文件)
2.9 反走样
抗锯齿( Antialiased)又称为反锯齿或者反走样,就是对图像的边缘进行平滑处
理,使其看起来更加柔和流畅的一种技术。QPainter 进行绘制时可以使用QPainter
::RenderHint 渲染提示来指定是否要使用抗锯齿功能,RenderHint 取值分为以下三
种。(这功能是在显卡中完成的)
常量 | 描述 |
---|---|
QPainter::Antialiasing | 边缘抗锯齿 |
QPainter::TextAntialiasing | 文字抗锯齿 |
– | – |
QPainter::SmoothPixmapTransform | 平滑pixmap转换算法抗锯齿 |
心法:
a) 绘制文字用TextAntialiasing
b)有图片用SmoothPixmapTransform
c)其它用 Antialiasing
2.10 渐变与填充
在Qt中提供了三种渐变方式,分别是线性渐变,圆形渐变和圆锥渐变。(可以使用来设计出炫目的填充效果)
线性渐变
QPainter painter(this);
//从点(100,150)开始到点(300,150)结束,确定一条直线
void Widget::paintEvent(QPaintEvent *event)
{
QLinearGradient linerGradient(100,150,300,150);
linerGradient.setColorAt(0,Qt::red);
linerGradient.setColorAt(0.2,Qt::black);
linerGradient.setColorAt(0.4,Qt::yellow);
linerGradient.setColorAt(0.6,Qt::white);
linerGradient.setColorAt(0.8,Qt::green);
linerGradient.setColorAt(1.0,Qt::blue);
//将直线开始点设为0,终点设为1,然后分段设置颜色
painter.setBrush(linerGradient);
painter.drawRect(100,100,200,200);
//绘制矩形,线性渐变线正好在矩形的水平中心线上
}
QPainter painter(this);
//其中参数分别为圆形渐变的圆心(200,100),半径100,和焦点(200,100)
//这里让焦点和圆心重合,从而形成从圆心向外渐变的效果
QRadialGradient radialGradient(200,100,100,200,100);
radialGradient.setColorAt(0,Qt::black);
radialGradient.setColorAt(1,Qt::yellow);
painter.setBrush(radialGradient);
painter.drawEllipse(100,0,200,200);
QPainter painter(this);
QConicalGradient conicalGradient(50,50,30);
//圆心为(50,50),开始角度为0
conicalGradient.setColorAt(0,Qt::green);
conicalGradient.setColorAt(1,Qt::white);
//从圆心的0度角开始逆时针填充
painter.setBrush(conicalGradient);
painter.drawEllipse(0,0,100,100);