渐变有三种:QLinearGradient,QConicalGradientandQRadialGradient,接下来将介绍它们的使用和实现原理。
一、QLinearGradient
QLinearGradient是线性渐变,也就是颜色的各个分量(red,green,blue)在两点之间的变化是线性的,需要设置渐变的起始和结束坐标、颜色,超出渐变范围的填充方式,它并不能单独的使用,而是要和QBrush一起使用实现填充效果,主要有以下一些函数:
//创建QLinearGradient,同时设置起始和结束坐标
QLinearGradient(constQPointFstart,constQPointFfinalStop)
QLinearGradient(qrealx1,qrealy1,qrealx2,qrealy2)
//设置渐变的颜色,position的取值范围是[0.0,1.0]
setColorAt(qrealposition,constQColorcolor)
//超出渐变范围后的填充方式,默认使用PadSpread:
//QGradient::PadSpread
//QGradient::RepeatSpread
//QGradient::ReflectSpread
voidsetSpread(Spreadmethod)
//使用渐变创建画刷
QBrush(constQGradientgradient)
下图来自QLinearGradient的帮助文档,两个灰色的点表示渐变的起始和结束位置,从黄色渐变到有点发灰的黄色,同时展示了超出渐变范围时的三种填充方式:
为了介绍QLinearGradient的使用,下面的程序使用线性渐变,在垂直方向从红色渐变到蓝色,填充矩形QRect(20,20,,):
voidLinearGradientWidget::paintEvent(QPaintEvent*){
QPainterpainter(this);
painter.setRenderHint(QPainter::Antialiasing);
QRectrect(20,20,,);
//渐变开始的坐标为(20,20),结束的坐标为(20,)
QLinearGradientgradient(rect.x(),rect.y(),
rect.x(),rect.y()+rect.height());
gradient.setColorAt(0.0,Qt::red);
gradient.setColorAt(1.0,Qt::blue);
//超出渐变范围后的填充方式
gradient.setSpread(QGradient::ReflectSpread);
painter.setPen(Qt::NoPen);
painter.setBrush(gradient);//QBrush(constQGradientgradient)
painter.drawRect(rect);
}
如果不用QLinearGradient,怎么实现上面的渐变效果呢?也既是线性渐变的原理是什么呢?
以求线段上任意点的坐标为例,如图,已知线段的两端点A(x1,y1),B(x2,y2),求线段上任意一点M的坐标(x,y),则
根据两点的距离公式可以求出线段的长度
AB
(用
表示线段的长度)
t=
AM
/
AB
;
因为
AM
=0且
AM
=
AB
,所以t的值为[0.0,1.0],用length表示
AB
,则
x=x1+t*length
y=y1+t*length
t为0.0时M和A重合,t为1.0时M和B重合。
因为t的值为0到1之间,所以可以用循环求出AB上任意点的坐标
for(floatt=0.0;rate=1.0;t+=0.1){
x=x1+t*length;
y=y1+t*length;
}
其实这就是线段的参数方程。
上面可以理解为坐标的渐变,变化的是坐标的x,y分量,颜色的渐变理论上也是一样的,只不过要变化的是颜色的R,G,B三个分量。如果同时已知点A,B的坐标和颜色(r1,g1,b1),(r2,g2,b2),那么M点的坐标和颜色为:
for(floatt=0.0;rate=1.0;t+=0.1){
x=x1+t*length;
y=y1+t*length;
r=r1+t*(r2-r1);
g=g1+t*(g2-g1);
b=b1+t*(b2-b1);
}
也既是说,如果知道某个点对应的t,那么就能计算出此点的颜色。如下图,要在矩形内沿着AB进行渐变填充,已知点A,B的坐标和颜色,在矩形内任意一点N的坐标也是已知的(循环遍历矩形内所有的点),那么就可以求出点N在AB上的投影M(MN垂直于AB),t=
AM
/
AB
,使用上面的方法求出点M的颜色,点M的颜色就是点N的颜色。
对于下图垂直方向的渐变来说,点A(x1,y1)为矩形的左上角,点B(x2,y2)为矩形的坐下角,矩形内任意一点N(x,y)在AB上的投影M的坐标为(x1,y),所以t=(y-y1)/(y2-y1),知道了t,那么就能计算出对应的颜色了。
voidLinearGradientAlgorithmWidget::paintEvent(QPaintEvent*){
QPainterpainter(this);
painter.setRenderHint(QPainter::Antialiasing);
//渐变填充的矩形
QRectrect(20,20,,);
//渐变开始和结束的颜色
QColorgradientStartColor(,0,0);
QColorgradientFinalColor(0,0,);
intr1,g1,b1,r2,g2,b2;
gradientStartColor.getRgb(r1,g1,b1);
gradientFinalColor.getRgb(r2,g2,b2);
qrealy1=rect.y();
qrealy2=rect.y()+rect.height();
//计算矩形中每一个点的颜色,然后用此颜色绘制这个点
for(intx=rect.x();x=rect.x()+rect.width();++x){
for(inty=rect.y();y=rect.y()+rect.height();++y){
qrealt=(y-y1)/(y2-y1);
t=qMax(0.0,qMin(t,1.0));
intr=r1+t*(r2-r1);
intg=g1+t*(g2-g1);
intb=b1+t*(b2-b1);
painter.setPen(QColor(r,g,b));
painter.drawPoint(x,y);
}
}
}
运行程序,看看效果是不是和使用QLinearGradient的一样?
对于下图这样指定渐变的开始和结束位置,非垂直和水平方向渐变的实现,关键是求任意一点在另一条线上的投影,有很多方法和公式可以使用,这里我们使用QTransform进行移动,旋转求出t,计算出对应的颜色,由于QTransform的知识比较复杂,这里就不作深入介绍,有兴趣的可以自行查看相关文档。
voidLinearGradientAlgorithm2Widget::paintEvent(QPaintEvent*){
QPainterpainter(this);
painter.setRenderHint(QPainter::Antialiasing);
//渐变填充的矩形
QRectrect(20,20,,);
//渐变开始和结束的颜色、位置
QColorgradientStartColor(,0,0);
QColorgradientFinalColor(0,0,);
QPointgradientStartPoint(60,60);
QPointgradientFinalPoint(,);
//颜色分量
intr1,g1,b1,r2,g2,b2;
gradientStartColor.getRgb(r1,g1,b1);
gradientFinalColor.getRgb(r2,g2,b2);
qrealdx=gradientFinalPoint.x()-gradientStartPoint.x();
qrealdy=gradientFinalPoint.y()-gradientStartPoint.y();
qreallength=qSqrt(dx*dx+dy*dy);//渐变开始和结束的线段的长度
floatradian=qAtan2(dy,dx);//渐变方向和X轴的夹角
//先移动,后旋转,要先调用旋转的函数,然后在调用移动的函数,一定要注意这点,
//因为底层实现是matrix矩阵右乘点的坐标的列矩阵
QTransformtransform;
transform.rotateRadians(-radian);
transform.translate(-gradientStartPoint.x(),-gradientStartPoint.y());
//计算矩形中每一个点的颜色,然后用此颜色绘制这个点
for(intx=rect.x();x=rect.x()+rect.width();++x){
for(inty=rect.y();y=rect.y()+rect.height();++y){
QPointFp=transform.map(QPointF(x,y));
qrealt=p.x()/length;
t=qMax(0.0,qMin(t,1.0));
intr=r1+t*(r2-r1);
intg=g1+t*(g2-g1);
intb=b1+t*(b2-b1);
painter.setPen(QColor(r,g,b));
painter.drawPoint(x,y);
}
}
}
t0或t1时,即超出渐变范围后的填充方式是需要考虑的,我们这里的实现就是PadSpread的方式,怎么实现RepeatSpread和ReflectSpread的渐变呢?这个就作为大家的作业吧。
二、QRadialGradient
QRadialGradient名为径向渐变,在圆的范围内进行渐变,有三个主要参数:圆心、半径、焦点:
QRadialGradient(constQPointFcenter,qrealradius,
constQPointFfocalPoint)
QRadialGradient(constQPointFcenter,qrealradius)
圆心和半径确定颜色渐变的范围,焦点是渐变开始的点,渐变结束的点在圆周上。很多人都认为径向渐变是从圆心开始渐变的,其实不是这样的,只不过焦点和圆心默认是在同一个位置,所以看上去渐变好像是从圆心开始。
如图,我们故意设置圆心和焦点不在同一个位置,这样就能很明显的看到渐变的范围,开始和结束的位置,连接焦点和圆周的线上的点的颜色做线性渐变(是不是知道怎么实现QRadialGradient了?)。
voidRadialGradientWidget::paintEvent(QPaintEvent*){
QPainterpainter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(width()/2,height()/2);
qrealradius=;//半径
QPointFcenter(0,0);//圆心
QPointFfocus(80,30);//焦点
//径向渐变
QRadialGradientgradient(center,radius,focus);
gradient.setColorAt(0.0,Qt::red);
gradient.setColorAt(1.0,Qt::blue);
//径向渐变填充圆
painter.setPen(Qt::darkGray);
painter.setBrush(gradient);
painter.drawEllipse(center,radius,radius);
//绘制圆心和焦点
painter.setBrush(Qt::gray);
painter.drawEllipse(center,4,4);
painter.drawEllipse(focus,4,4);
}
三、QConicalGradient
QConicalGradient名为角度渐变,在同一条半径上的像素的颜色值是相同的,只需要指定渐变的中心和开始的角度:
QConicalGradient(constQPointFcenter,qrealangle)
QConicalGradient(qrealcx,qrealcy,qrealangle)
经过线性渐变和径向渐变的学习,相信现在大家都能很容易的推断得出角度渐变的原理,这里就不作解释,作为悬念留给大家吧。
voidConicalGradientWidget::paintEvent(QPaintEvent*){
QPainterpainter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(width()/2,height()/2);
qrealstartAngle=45;//渐变开始的角度
QPointFcenter(0,0);//渐变的中心
QConicalGradientgradient(center,startAngle);
gradient.setColorAt(0.0,Qt::red);
gradient.setColorAt(0.33,Qt::green);
gradient.setColorAt(0.66,Qt::blue);
gradient.setColorAt(1.0,Qt::red);
painter.setPen(Qt::darkGray);
painter.setBrush(gradient);
painter.drawEllipse(center,,);
}
声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。学到牛牛IT培训