毕设笔记——Qt不规则图形的渐变填充
需求说明
最近写毕设时,需要利用Qt实现一个引向天线设计优化的软件,最近刚把计算模型搭建完毕,准备开始GUI界面设计。我的计划是先从天线的示意图开始做起,从一本天线英文书看到的示意图还不错,准备用Qt场景图元实现之,这样也方便用户添加与删除振子。
实现方法
关键类的认识
QPainterPath
简介
从描述中可以看到,一个QPainterPath可以看成是存放一些图形单元的容器,可以是线,椭圆最关键的是,他能用于填充,这是完成本需求的关键之一。
moveTo函数
这个函数形象地说,就是假设你手上拿着一支笔,你要从哪一点开始画起,但请注意他的说明:closing the previous one,也就是说,你如果前面添加的不是闭合曲线,该函数会将其闭合,比如你画了一个段弧,起始点为(x1,y1),终点为(x2,y2),你最后画完了调用moveTo(x1,y1)从终点回到起点,该函数会在(x1,y1)和(x2,y2)之间连一条直线使其闭合。
actTo函数
这是一个往QPainterPath添加圆弧的函数,参数分别为弧的外接矩形,开始角度,扫过的角度
lineTo
连线功能,连接当前点和指定的结束点。
注意:QPainterPath当前点是一直在变化的。假设你有一只笔,你画一条直线,你笔现在的所在位置就是QPainterPath的当前点
QLinearGradient
简介
渐变主要是通过该类实现的,可以从中看到,PadSpread方式和ReflectSpread方式都是可以实现该效果的。
通过该描述可以知道,我们可以通过SetColorAt函数添加一些点的颜色,该类会实现你指定的两点(两种颜色)之间的渐变效果。
setColorAt函数
position参数相当于归一化处理,0为起始点,1为结束点,比如0.5为中间点,我们也可以添加很多个中间点(取值为0-1),插入很多个颜色。就拿我们要实现的需求来说,我们要实现从灰->白->灰这样的效果,我添加的三个点为(0,灰色)、(0.7,白色)、(1,灰色)
踩坑过程
盲目抄手册
看到手册那个arcTo函数的用法举例后,我以为要先调用moveTo把当前点移动到椭圆中心点,最后画出的图像是
中间多出来了一条线,搜了其他人的博客才发现这个问题
没有指定渐变类的起始点与终点
我直接用
没有参数的构造函数(因为前面手册也没有参数),导致我的柱子依然是白色的,没有渐变色。仔细看了一下手册才发现需要指定起始点和终点,这样子就是指定了渐变的方向,从起始点——>终点
乱用moveTo函数
没有看到moveTo的后半段说明,画一段调用一次moveTo,导致画出来的图像很不对
注意往QPainterPath添加曲线时,一定要想象你如何一口气画完不规则曲线,而不要中间使用moveTo
最终结果与代码
无源振子
/*
* 功能:绘制一根天线
* 参数:天线的中心点,天线的长度,天线的半径
*
*
* */
void Widget::drawAntPassive(QPointF center, qreal length,qreal radius)
{
QPainter pr(this);
pr.setRenderHint(QPainter::Antialiasing, true);//打开反走样
QPen pen;
pen.setWidthF(3); //画笔相关
pr.setPen(pen);
QRectF rect(QPointF(center.x()-radius,center.y()-length-radius/2),
QPointF(center.x()+radius,center.y()-length+radius/2)); //顶部椭圆外接矩形
QRectF rect2(QPointF(center.x()-radius,center.y()+length-radius/2),
QPointF(center.x()+radius,center.y()+length+radius/2));//绘制棍子底部弧所需外接矩形
pr.drawArc(rect,0,180*16); //绘制棍子顶部椭圆的半圆,仿三维,因为顶部椭圆无色,接下去要用QPointerPath
QPainterPath myPath;
//这里画待填充渐变的区域,注意中间不要使用moveTo
myPath.moveTo(center.x()-radius,center.y()-length);
myPath.arcTo(rect,180.0f,180.0f); //绘制上椭圆下半圆
myPath.lineTo(QPointF(center.x()+radius,center.y()+length)); //右边竖线
myPath.arcTo(rect2,0,-180.0f);
myPath.lineTo(QPointF(center.x()-radius,center.y()-length)); //左边竖线
QLinearGradient myGradient(QPointF(center.x()-radius,center.y()),QPointF(center.x()+radius,center.y()));
//一定要指定开始点和结束点,标明绘制的方向,才能正常绘制渐变,这是我踩的一个坑
//仿三维,渐变色
//myGradient.setSpread(QGradient::ReflectSpread);
myGradient.setColorAt(0,QColor(QString("#474747")));
myGradient.setColorAt(0.7,QColor(QString("#FFFFFF")));
myGradient.setColorAt(1,QColor(QString("#878787")));
QBrush brh(myGradient);
pr.setBrush(brh);
pr.drawPath(myPath);
}
有源振子
有源振子只要在无源振子下加画一个源即可。代码如下
/**
* @brief Widget::drawAntActive
* @param center 天线的中点
* @param length 天线的长度
* @param radius 天线的半径
*/
void Widget::drawAntActive(QPointF center, qreal length, qreal radius)
{
drawAntPassive(center,length,radius);
//以下为绘制源
QPainter pr(this);
pr.setRenderHint(QPainter::Antialiasing, true);//打开反走样
QPen pen;
pen.setWidth(3);
pr.setPen(pen);
pr.setBrush(QBrush(Qt::white));
QRectF rect(QPointF(center.x()-2*radius,center.y()-2*radius),
QPointF(center.x()+2*radius,center.y()+2*radius)); //外部圆的外接矩形
pr.drawEllipse(rect); //源外部圆的绘制
QRectF rect2(QPointF(center.x()-radius,center.y()-radius/2),
QPointF(center.x(),center.y()+radius/2)); //外接矩形1
pr.drawArc(rect2,0,180*16);
QRectF rect3(QPointF(center.x(),center.y()-radius/2),
QPointF(center.x()+radius,center.y()+radius/2)); //外接矩形2
pr.drawArc(rect3,0,-180*16);
}
接下去只需要将这两个函数写进QGraphicsItem的paint虚函数即可