一、效果图
二、效果图拆解
根据效果图上显示,常规模式的小贝是由多个同心圆组成的,最外圈是一个圆圈,然后是一个白色的圆环,圆环上绘制渐变色进度条,再里面是一个边缘向中心渐变的圆形渐变圆,最中间的文字是三个标签组成的。
三、绘制过程拆解
①首先绘制一个圆圈,颜色指定为灰色即可。
②将半径减少一个像素,绘制一个填充的带透明度的白色圆。
③半径不变,从90°开始顺时针绘制锥形渐变扇形圆环。
④半径减小,留出进度条显示的宽度,绘制一个带有透明度的圆圈。
⑤半径再减小一个像素,绘制一个带有透明度的圆形渐变圆。
⑥设置中间控件上的文字变化。
四、准备工作
①初始化窗口类,类继承自QDialog,设置窗口大小,去掉标题栏,任务栏,窗口置顶等,代码如下所示:
setFixedSize(70,70);
//去掉标题栏 设置置顶 去掉任务栏图标
setWindowFlags(Qt::FramelessWindowHint|Qt::Tool|Qt::WindowCloseButtonHint|Qt::WindowStaysOnTopHint);
②设置控件再主屏幕上的显示位置,将窗口移动到主屏幕右下角位置,代码如下:
//获取主屏尺寸 设置位置
QScreen *primaryScreen=QGuiApplication::primaryScreen();
if(primaryScreen==nullptr)
return;
geometry=primaryScreen->availableGeometry();
this->move(geometry.width()-100,geometry.height()*0.6);
③很重要的一点,设置窗口背景透明,如果不设置这个,窗口运行起来就是有一个白色背景,设置代码如下:
//设置窗口背景透明
setAttribute(Qt::WA_TranslucentBackground, true);
④设置窗口可以随着鼠标拖动而移动,这里需要重写QWidget类的三个虚函数方法,分别是:
void mousePressEvent(QMouseEvent*);
void mouseMoveEvent(QMouseEvent*);
void mouseReleaseEvent(QMouseEvent*);
实现代码如下所示:
//定义变量-记录最后的移动位置
QPoint last;
//实现三个虚函数
void GuardXiaobei::mousePressEvent(QMouseEvent *e)
{
last = e->globalPos();
}
void GuardXiaobei::mouseMoveEvent(QMouseEvent *e)
{
if((last.x()==0)&&(last.y()==0))
return;
int dx = e->globalX() - last.x();
int dy = e->globalY() - last.y();
last = e->globalPos();
this->move(x()+dx, y()+dy);
}
void GuardXiaobei::mouseReleaseEvent(QMouseEvent *e)
{
if((last.x()==0)&&(last.y()==0))
return;
int dx = e->globalX() - last.x();
int dy = e->globalY() - last.y();
this->move(x() + dx, y() + dy);
}
五、详细绘制过程
①首先初始化必要的变量,比如设置圆圈的半径大小(这里默认设置为35像素),初始化界面上显示百分比的几个控件,设置对齐方式等,设置几个控件的代码如下:
//初始化控件
lab_Value=new QLabel();
QLabel *lab_Unit=new QLabel();
QLabel *lab_NetSpeed=new QLabel();
QHBoxLayout* valueLayout=new QHBoxLayout();
QVBoxLayout* mainLayout=new QVBoxLayout();
//设置控件样式
lab_Value->setFont(QFont("宋体",18));
//设置控件文字
lab_Value->setText("25");
lab_Unit->setText("%");
lab_NetSpeed->setText("0K/s");
//设置控件文字对齐方式
lab_Value->setAlignment(Qt::AlignHCenter|Qt::AlignBottom);
lab_Unit->setAlignment(Qt::AlignHCenter|Qt::AlignBottom);
lab_NetSpeed->setAlignment(Qt::AlignHCenter|Qt::AlignTop);
lab_Value->setFixedHeight(40);
lab_Unit->setFixedHeight(36);
//设置布局
valueLayout->setMargin(0);
valueLayout->setSpacing(0);
valueLayout->addStretch(1);
valueLayout->addWidget(lab_Value);
valueLayout->addWidget(lab_Unit);
valueLayout->addStretch(1);
mainLayout->setMargin(0);
mainLayout->setSpacing(0);
mainLayout->addLayout(valueLayout,3);
mainLayout->addWidget(lab_NetSpeed,2);
setLayout(mainLayout);
②重载QWidget的绘图函数paintEvent。初始化绘图的QPainter对象,启用反锯齿,将绘制中心移动到控件中心,代码如下所示:
QPainter painter(this);
//启动反锯齿
painter.setRenderHint(QPainter::Antialiasing, true);
//将画笔中心点移动到窗体中心
painter.translate(this->width()/2,this->height()/2);
③绘制外圆环,颜色值为RGB(230,230,230),透明度为100(完全不透明为255),代码入下所示:
//调用代码
DrawLineEllipse(painter,radius,QColor(230,230,230,100));
实现代码
void GuardXiaobei::DrawLineEllipse(QPainter& painter,int r,QColor color)
{
QBrush brush(color);
painter.setPen(QPen(brush,1,Qt::SolidLine));
painter.setBrush(brush);
painter.drawEllipse(-r,-r,r<<1,r<<1);
}
效果图如下所示,由于我桌面是蓝色的,窗口背景被设置成了透明,所以这里看到的是蓝色背景:
④绘制中间的带透明度的圆,代码如下所示:
//调用代码如下,半径减小一个像素,颜色值为白色,透明度为50
DrawConicalGradientFullArc(painter,radius-1,QColor(255,255,255,50));
//实现代码如下
void GuardXiaobei::DrawConicalGradientFullArc(QPainter& painter,int r,QColor color)
{
QConicalGradient conicalGradient(QPointF(0, 0), 90);
conicalGradient.setColorAt(0, color);
conicalGradient.setColorAt(1.0, color);
painter.setBrush(conicalGradient);
painter.drawEllipse(QPoint(0,0),r,r);
}
效果图如下,同样由于设置了透明度,所以背景会受到桌面颜色的影响:
⑤绘制中间带有圆形渐变色的进度条,实际是绘制一个整圆,中间绘制遮罩,实现环状效果,代码如下:
//调用代码如下,设置进度条开始位置颜色为绿色,结束位置颜色为红色
DrawConicalGradientArc(painter,radius-1,QColor(86,229,108),QColor(255,0,0));
实现代码如下
void GuardXiaobei::DrawConicalGradientArc(QPainter& painter,int r,QColor startColor,QColor endColor)
{
// 渐变色
QConicalGradient conicalGradient(QPointF(0, 0), 90);
conicalGradient.setColorAt(0,endColor);
conicalGradient.setColorAt(1.0, startColor);
painter.setBrush(conicalGradient);
QRectF rect(-r,-r,r<<1,r<<1);
QPainterPath path;
path.arcTo(rect,currentAngle,90-currentAngle);
painter.setPen(Qt::NoPen);
painter.drawPath(path);
}
效果图如下所示,这里第一个图红色部分不明显,因为设置的是终点为红色,中间都为过渡渐变色:
⑥绘制内圆环,颜色值设置为绿色,代码如下所示:
//调用代码如下
DrawLineEllipse(painter,radius-6,QColor(21,207,96,150));
实现代码如下
void GuardXiaobei::DrawLineEllipse(QPainter& painter,int r,QColor color)
{
QBrush brush(color);
painter.setPen(QPen(brush,1,Qt::SolidLine));
painter.setBrush(brush);
painter.drawEllipse(-r,-r,r<<1,r<<1);
}
效果图如下所示:
⑦绘制一个中心遮罩,将中间多余的绿色遮住,代码如下所示:
//调用代码如下,设置颜色值为RGB(230,230,230)
DrawConicalGradientFullArc(painter,radius-6,QColor(230,230,230));
//实现代码如下
void GuardXiaobei::DrawConicalGradientFullArc(QPainter& painter,int r,QColor color)
{
QConicalGradient conicalGradient(QPointF(0, 0), 90);
conicalGradient.setColorAt(0, color);
conicalGradient.setColorAt(1.0, color);
painter.setBrush(conicalGradient);
painter.drawEllipse(QPoint(0,0),r,r);
}
效果图如下所示:
⑧绘制一个带透明度的锥形渐变圆,代码如下所示:
//调用代码如下,设置边缘颜色为绿色,透明度为80,中心颜色为白灰色
DrawRadialGradientArc(painter,radius-7,QColor(21,207,96,80),QColor(230,230,230));
实现代码如下所示
void GuardXiaobei::DrawRadialGradientArc(QPainter& painter,int r,QColor startColor,QColor endColor)
{
QRadialGradient radialGradient(0,0,r,0,0);
radialGradient.setColorAt(0.7,endColor);
radialGradient.setColorAt(1,startColor);
painter.setBrush(radialGradient);
painter.drawEllipse(-r,-r,r<<1,r<<1);
}
其中setColorAt中1表示边缘的颜色,0.7是半径的70%处显示白色。
效果图如下所示:
到此,绘制小贝常规模式的UI界面完成,由于截图背景色没有处理,所以截图上四个角落有蓝色,最后是百分比和角度的对应关系转换,比如现在的25%对应的角度是0°,对应转换代码如下:
value的值范围是0-100
currentAngle=-(value/100.0)*360+90;
六、最后总结
①目前只是实现了悬浮球的鼠标点击拖动,并没有做悬浮球碰到边界的检测和贴边收缩功能。后续增加这个功能。
②上面描述的是绘制的整个过程,源码中,给出了设置开一系列参数设置函数,可以根据自身需要设置不同的值,实现不同的效果。
七、代码获取
从Git下载,地址为:https://github.com/youyicc/GuardXiaobei.git