ukui-clock/qroundProgressBar.cpp

392 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* QRoundProgressBar - a circular progress bar Qt widget.
*
* Sintegrial Technologies (c) 2015-now
*
* The software is freeware and is distributed "as is" with the complete source codes.
* Anybody is free to use it in any software projects, either commercial or non-commercial.
* Please do not remove this copyright message and remain the name of the author unchanged.
*
* It is very appreciated if you produce some feedback to us case you are going to use
* the software.
*
* Please send your questions, suggestions, and information about found issues to the
*
* sintegrial@gmail.com
*
*/
#include "qroundProgressBar.h"
#include <QtGui/QPainter>
#include <QtGui/QPainterPath>
#include <QDebug>
#include <QStyleOption>
//#include <QGSettings>
QRoundProgressBar::QRoundProgressBar(QWidget *parent) :
QWidget(parent),
m_min(0), m_max(100),
m_value(25),
m_nullPosition(PositionTop),
m_barStyle(StyleDonut),
m_outlinePenWidth(0.96),
m_dataPenWidth(1),
m_rebuildBrush(false),
m_format("%p%"),
m_decimals(1),
m_updateFlags(UF_PERCENT)
{
settingsStyle();
}
void QRoundProgressBar::setRange(double min, double max)
{
m_min = min;
m_max = max;
if (m_max < m_min)
qSwap(m_max, m_min);
if (m_value < m_min)
m_value = m_min;
else if (m_value > m_max)
m_value = m_max;
if (!m_gradientData.isEmpty())
m_rebuildBrush = true;
update();
}
void QRoundProgressBar::setMinimum(double min)
{
setRange(min, m_max);
}
void QRoundProgressBar::setMaximum(double max)
{
setRange(m_min, max);
}
void QRoundProgressBar::setValue(double val)
{
if (m_value != val) {
if (val < m_min)
m_value = m_min;
else if (val > m_max)
m_value = m_max;
else
m_value = val;
update();
}
}
//定义最小值位置
void QRoundProgressBar::setNullPosition(double position)
{
if (position != m_nullPosition) {
m_nullPosition = position;
if (!m_gradientData.isEmpty())
m_rebuildBrush = true;
update();
}
}
//设置视觉样式圆环(甜甜圈)风格、饼(派)风格、线型
void QRoundProgressBar::setBarStyle(QRoundProgressBar::BarStyle style)
{
if (style != m_barStyle) {
m_barStyle = style;
update();
}
}
//设置轮廓圆笔的宽度。
void QRoundProgressBar::setOutlinePenWidth(double penWidth)
{
if (penWidth != m_outlinePenWidth) {
m_outlinePenWidth = penWidth;
update();
}
}
//设置数据圆笔的宽度。
void QRoundProgressBar::setDataPenWidth(double penWidth)
{
if (penWidth != m_dataPenWidth) {
m_dataPenWidth = penWidth;
update();
}
}
//设置可见数据的颜色,并使用它们制作渐变画笔。
//此函数将覆盖widget的`palette`来设置动态创建的渐变笔刷
void QRoundProgressBar::setDataColors(const QGradientStops &stopPoints)
{
if (stopPoints != m_gradientData) {
m_gradientData = stopPoints;
m_rebuildBrush = true;
update();
}
}
//定义用于生成当前文本的字符串。
//p-用完成的百分比代替。 v-由当前值替换。 m-由最大值代替。
//默认值为“p
void QRoundProgressBar::setFormat(const QString &format)
{
if (format != m_format) {
m_format = format;
valueFormatChanged();
}
}
//将格式字符串设置为空字符串。 因此,将不会显示任何文本。
void QRoundProgressBar::resetFormat()
{
m_format = QString::null;
valueFormatChanged();
}
//设置要在逗号后显示的小数位数默认为1
void QRoundProgressBar::setDecimals(int count)
{
if (count >= 0 && count != m_decimals) {
m_decimals = count;
valueFormatChanged();
}
}
void QRoundProgressBar::paintEvent(QPaintEvent* /*event*/)
{
//构造和自定义例如设置笔或画笔painter。 然后画。 记住在绘制后销毁QPainter对象。
QPainter painter(this);
painter.save();
//mainColor 在settingsStyle配置
painter.setPen(mainColor);
painter.setBrush(mainColor);
//在指定的boundingRectangle中创建一个椭圆并将其作为封闭的子路径添加到painter路径。
QPainterPath bigCircle;
bigCircle.addEllipse(65, 13, 266, 266);
QPainterPath path = bigCircle ;
painter.drawPath(path);
//保存当前的画家状态(将状态推送到堆栈上)。 在save之后必须有一个相应的restore end函数展开堆栈。
painter.restore();
double outerRadius = 133;
QRectF baseRect(198 - outerRadius, 146 - outerRadius, outerRadius * 2, outerRadius * 2);
QPainter p(this);
//表示引擎应尽可能对图元的边缘进行抗锯齿。
p.setRenderHint(QPainter::Antialiasing);
// data brush
rebuildDataBrushIfNeeded();
// background
drawBackground(p, rect());
double innerRadius = 133;
QRectF innerRect = QRectF((198 - outerRadius) + 5, (146 - outerRadius) + 5, (outerRadius - 5) * 2 , (outerRadius - 5) * 2 );
//calculateInnerRect(baseRect, outerRadius, innerRect, innerRadius);
double arcStep = 360.0 / (m_max - m_min) * m_value;
// base circle
drawBase(p, baseRect,innerRect);
// data circle
drawValue(p, baseRect, m_value, arcStep,innerRect, innerRadius);
// finally draw the bar
p.end();
}
//背景色
void QRoundProgressBar::drawBackground(QPainter &p, const QRectF &baseRect)
{
p.fillRect(baseRect, palette().background());
}
//画基础
void QRoundProgressBar::drawBase(QPainter &p, const QRectF &baseRect,const QRectF &innerRect)
{
QStyleOption opt;
opt.init(this);
switch (m_barStyle)
{
case StyleDonut:
// p.setPen(QPen(QColor(160, 160, 160), 4, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
// p.setBrush(Qt::NoBrush);
// p.drawEllipse(QPointF(227, 180),155,155);
break;
case StylePie:
p.setPen(QPen(palette().base().color(), m_outlinePenWidth, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
p.setBrush(palette().base());
p.drawEllipse(baseRect);
break;
case StyleLine:
p.setPen(QPen(palette().base().color(), m_outlinePenWidth ,Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
p.setBrush(Qt::NoBrush);
p.drawEllipse(baseRect.adjusted(m_outlinePenWidth/2, m_outlinePenWidth/2, -m_outlinePenWidth/2, -m_outlinePenWidth/2));
break;
default:;
}
}
//画数据
void QRoundProgressBar::drawValue(QPainter &p
, const QRectF &baseRect
, double value
, double arcLength
, const QRectF & innerRect
, double innerRadius)
{
// nothing to draw
if (value == m_min)
return;
// for Pie and Donut styles
QPainterPath dataPath;
dataPath.setFillRule(Qt::WindingFill);
dataPath.moveTo(baseRect.center());
dataPath.arcTo(baseRect, m_nullPosition, -arcLength);//大家都是先绘制外圆的弧长
if(m_barStyle == StyleDonut) {
// draw dount outer
QPointF currentPoint = dataPath.currentPosition();//绘制完外圆弧长后,获取绘制完的位置绘制一个直线到达内圆
currentPoint = baseRect.center() + (currentPoint - baseRect.center()) * m_innerOuterRate;//计算内圆的坐标点m_innerOuterRate替代了原作者写的0.75代表内圆是外圆的0.75倍
dataPath.lineTo(currentPoint);//绘制外圆到内圆的直线
dataPath.moveTo(baseRect.center());//坐标点回到中心准备绘制内圆弧形
dataPath.arcTo(innerRect, m_nullPosition-arcLength, arcLength);//绘制内圆的弧形
currentPoint = dataPath.currentPosition();//准备绘制内圆到外圆的直线,形成封闭区域
currentPoint = baseRect.center() + ((currentPoint - baseRect.center()) * (2-m_innerOuterRate));//绘制内圆到外圆的直线这里2-m_innerOuterRate其实是对应(1 + (1 -m_innerOuterRate))的
dataPath.lineTo(currentPoint);
p.setPen(Qt::NoPen);//这个很重要不然就会有绘制过程的一些轮廓了
}
p.setBrush(palette().highlight());
p.setBrush(ringRunColor);
p.drawPath(dataPath);
}
void QRoundProgressBar::calculateInnerRect(const QRectF &/*baseRect*/, double outerRadius, QRectF &innerRect, double &innerRadius)
{
// for Line style
if (m_barStyle == StyleLine) {
innerRadius = outerRadius - m_outlinePenWidth;
} else {
innerRadius = outerRadius * m_outlinePenWidth;
}
double delta = (outerRadius - innerRadius) / 2;
innerRect = QRectF(delta, delta, innerRadius, innerRadius);
// innerRect = QRectF(227 - outerRadius, 220 - outerRadius, innerRadius * 2, innerRadius * 2);
}
void QRoundProgressBar::drawInnerBackground(QPainter &p, const QRectF &innerRect)
{
if (m_barStyle == StyleDonut) {
p.setBrush(palette().alternateBase());
p.drawEllipse(innerRect);
}
}
void QRoundProgressBar::drawText(QPainter &p, const QRectF &innerRect, double innerRadius, double value)
{
if (m_format.isEmpty())
return;
// !!! to revise
QFont f(font());
f.setPixelSize(innerRadius * qMax(0.05, (0.35 - (double)m_decimals * 0.08)));
p.setFont(f);
QRectF textRect(innerRect);
p.setPen(palette().text().color());
p.drawText(textRect, Qt::AlignCenter, valueToText(value));
}
QString QRoundProgressBar::valueToText(double value) const
{
QString textToDraw(m_format);
if (m_updateFlags & UF_VALUE)
textToDraw.replace("%v", QString::number(value, 'f', m_decimals));
if (m_updateFlags & UF_PERCENT) {
double procent = (value - m_min) / (m_max - m_min) * 100.0;
textToDraw.replace("%p", QString::number(procent, 'f', m_decimals));
}
if (m_updateFlags & UF_MAX)
textToDraw.replace("%m", QString::number(m_max - m_min + 1, 'f', m_decimals));
return textToDraw;
}
void QRoundProgressBar::valueFormatChanged()
{
m_updateFlags = 0;
if (m_format.contains("%v"))
m_updateFlags |= UF_VALUE;
if (m_format.contains("%p"))
m_updateFlags |= UF_PERCENT;
if (m_format.contains("%m"))
m_updateFlags |= UF_MAX;
update();
}
void QRoundProgressBar::rebuildDataBrushIfNeeded()
{
if (m_rebuildBrush) {
m_rebuildBrush = false;
QConicalGradient dataBrush;
dataBrush.setCenter(0.5,0.5);
dataBrush.setCoordinateMode(QGradient::StretchToDeviceMode);
// invert colors
for (int i = 0; i < m_gradientData.count(); i++) {
dataBrush.setColorAt(1.0 - m_gradientData.at(i).first, m_gradientData.at(i).second);
}
// angle
dataBrush.setAngle(m_nullPosition);
QPalette p(palette());
p.setBrush(QPalette::Window,Qt::NoBrush);
p.setBrush(QPalette::AlternateBase,Qt::NoBrush);
p.setBrush(QPalette::Highlight, dataBrush);
setPalette(p);
}
}
QColor QRoundProgressBar::getRingRunColor() const
{
return ringRunColor;
}
void QRoundProgressBar::setRingRunColor(const QColor &value)
{
ringRunColor = value;
}
void QRoundProgressBar::switchRunRingColor()
{
ringRunColor = QColor(55, 144, 250,255);
update();
}
void QRoundProgressBar::switchStopRingColor()
{
ringRunColor = QColor(69, 173, 110,255);
update();
}
/*
*监听主题
*/
void QRoundProgressBar::settingsStyle()
{
GsettingSubject * subject = GsettingSubject::getInstance();;
connect(subject,&GsettingSubject::blackStyle, this,[=](){
mainColor = QColor(255, 255, 255, 40);
});
connect(subject,&GsettingSubject::whiteStyle, this,[=](){
mainColor = QColor(255, 255, 255, 107);
});
subject->iniWidgetStyle();
}