效果图

功能
- 支持鼠标左键按下并拖动
- 支持移动到鼠标按下的位置。
- 支持线显示当前的数值
- 支持设置滑块等颜色
完整代码
LineProgressBar.h
#pragma once
#include <QAbstractSlider>
#include "WidgetPackSymbol.hpp"
class WIDGET_PACK_API LineProgressBar : public QAbstractSlider
{
Q_OBJECT
public:
explicit LineProgressBar(QWidget *parent = nullptr);
virtual ~LineProgressBar();
void setRange(qreal nMin, qreal nMax);
qreal value()const;
/// 设置填充部分的颜色
void setFillValueColor(const QString& str);
/// 设置没有填充部分的颜色
void setUnfillValueColor(const QString& str);
///
/// @brief: 设置当前值显示的颜色,
/// @param: str 比如: #FF00FF
/// @return: void
///
void setValueTextColor(const QString& str);
protected:
virtual void paintEvent(QPaintEvent *event)override;
virtual void mouseMoveEvent(QMouseEvent *event)override;
virtual void mousePressEvent(QMouseEvent *event)override;
virtual void mouseReleaseEvent(QMouseEvent *event)override;
private:
void updateValue(qreal nCurValue);
void initValue();
void initUISetting();
signals:
void sigValueChanged(qreal nValue);
public slots:
void slotSetValue(qreal nValue);
private:
struct stRange
{
qreal m_nMin{0.0};
qreal m_nMax{100.0};
}m_range;
qreal m_nCurValue{0};
qreal m_dbCurPercent{0.0};
qreal m_dbRadius{10.0};
bool m_bPressed{false};
/// 文字的颜色, 比如: "#FF00FF"
QString m_valueTextColor{"#111111"};
/// 当前数值划过的数值滑块颜色
QString m_currentValueColor{"#39CE99"};
/// 没有划过的数值滑块颜色
QString m_invalidValueColor{"#BBBBBB"};
};
LineProgressBar.cpp
#include "LineProgressBar.h"
#include <QPainter>
#include <QMouseEvent>
#include <QFontMetrics>
#include <QLinearGradient>
#include <QDebug>
LineProgressBar::LineProgressBar(QWidget* parent)
: QAbstractSlider(parent)
{
initUISetting();
initValue();
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
}
LineProgressBar::~LineProgressBar()
{
}
void LineProgressBar::setRange(qreal nMin, qreal nMax)
{
if (nMax < nMin)
{
nMax = nMin;
}
m_range.m_nMin = nMin;
m_range.m_nMax = nMax;
updateValue(0);
}
void LineProgressBar::slotSetValue(qreal nValue)
{
updateValue(nValue);
}
qreal LineProgressBar::value() const
{
return m_nCurValue;
}
///
/// @brief: setFillRectColor
/// @param: lg
/// @return: void
///
void LineProgressBar::setFillValueColor(const QString& str)
{
if (m_currentValueColor == str)
{
return;
}
m_currentValueColor = str;
update();
}
///
/// @brief: setUnfillValueColor
/// @param: str
/// @return: void
///
void LineProgressBar::setUnfillValueColor(const QString& str)
{
if (str == m_invalidValueColor)
{
return;
}
m_invalidValueColor = str;
update();
}
///
/// @brief: 设置当前值显示的颜色
/// @param: str
/// @return: void
///
void LineProgressBar::setValueTextColor(const QString& str)
{
m_valueTextColor = str;
update();
}
void LineProgressBar::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
QPainter painter(this);
painter.setPen(Qt::NoPen);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.setBrush(Qt::NoBrush);
QSizeF currentValueSize{ 50, height()*1.0 };
// 绘制 Slider 轨道
QRectF sliderRect(m_dbRadius, height() / 2 - 5, width() - m_dbRadius* 2 - currentValueSize.width(), m_dbRadius);
{
// Slider 轨道的尺寸
qreal trackHeight = m_dbRadius;
qreal cornerRadius = trackHeight / 2;
QRectF sliderRectAA(m_dbRadius, (height() - trackHeight) / 2, sliderRect.width(), trackHeight);
// 绘制未划过的区域(灰色)
QPainterPath trackPath;
trackPath.addRoundedRect(sliderRect, cornerRadius, cornerRadius);
painter.setPen(Qt::NoPen);
painter.setBrush(QBrush(QColor(m_invalidValueColor)));
painter.drawPath(trackPath);
// 绘制划过的区域(绿色)
QPainterPath filledPath{};
qreal sliderWidth = sliderRect.width() * m_dbCurPercent;
QRectF knobRect(sliderRect.x(), sliderRect.y(), sliderWidth, trackHeight);
filledPath.addRoundedRect(knobRect, m_dbRadius / 2, m_dbRadius / 2);
painter.setBrush(QColor(m_currentValueColor));
painter.drawPath(filledPath);
}
qreal sliderWidth = sliderRect.width() * 1.0;
// 绘制滑块
qreal x = sliderRect.x() + sliderWidth * m_dbCurPercent;
QRectF knobRect(x - m_dbRadius, sliderRect.center().y() - m_dbRadius, 2 * m_dbRadius, 2 * m_dbRadius);
//painter.setBrush(QColor("#40508D"));
painter.setBrush(QColor(m_currentValueColor));
painter.setPen(Qt::NoPen);
// 绘制圆形滑块
painter.drawEllipse(knobRect);
painter.setPen(QColor(m_valueTextColor));
painter.setBrush(Qt::NoBrush);
QFont ft = painter.font();
ft.setPointSizeF(10.0);
painter.setFont(ft);
QRectF currentValueRect(QPointF(sliderRect.x() + m_dbRadius + sliderRect.width(), 0), currentValueSize);
painter.drawText(currentValueRect, Qt::AlignLeft | Qt::AlignVCenter, QString::number(m_nCurValue, 'f', 1));
}
void LineProgressBar::mouseMoveEvent(QMouseEvent* event)
{
if (m_bPressed)
{
QSizeF currentValueSize{ 50, height() * 1.0 };
// 绘制 Slider 轨道
QRectF sliderRect(m_dbRadius, height() / 2 - 5, width() - m_dbRadius * 2 - currentValueSize.width(), m_dbRadius);
QPoint pressPoint = event->pos();
if (true == sliderRect.contains(pressPoint))
{
m_dbCurPercent = ((event->pos().x() - sliderRect.x()) * 1.0) / sliderRect.width();
m_nCurValue = (m_range.m_nMax - m_range.m_nMin) * m_dbCurPercent;
update();
emit sigValueChanged(m_nCurValue);
}
/// 在外面
else
{
int pressXX = pressPoint.x();
/// 移动到最右侧
if (pressXX > (sliderRect.width() + sliderRect.x()))
{
m_dbCurPercent = 1.0;
m_nCurValue = (m_range.m_nMax - m_range.m_nMin) * m_dbCurPercent;
emit sigValueChanged(m_nCurValue);
update();
}
else if (pressXX < sliderRect.x())
{
m_dbCurPercent = 0.0;
m_nCurValue = (m_range.m_nMax - m_range.m_nMin) * m_dbCurPercent;
update();
emit sigValueChanged(m_nCurValue);
}
else
{
m_dbCurPercent = ((event->pos().x() - sliderRect.x()) * 1.0) / sliderRect.width();
m_nCurValue = (m_range.m_nMax - m_range.m_nMin) * m_dbCurPercent;
update();
emit sigValueChanged(m_nCurValue);
}
}
}
QWidget::mouseMoveEvent(event);
}
void LineProgressBar::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
/// 如果是鼠标左键单击
if (QEvent::MouseButtonPress == event->type())
{
QSizeF currentValueSize{ 50, height() * 1.0 };
// 绘制 Slider 轨道
QRectF sliderRect(m_dbRadius, height() / 2 - 5, width() - m_dbRadius * 2 - currentValueSize.width(), m_dbRadius);
QPoint pressPoint = event->pos();
QRectF checkSliderRect(sliderRect);
checkSliderRect.setX(sliderRect.x() - m_dbRadius);
checkSliderRect.setY(sliderRect.y() - m_dbRadius);
checkSliderRect.setWidth(sliderRect.width() + m_dbRadius * 2);
checkSliderRect.setHeight(sliderRect.height() + m_dbRadius * 2);
if (true == checkSliderRect.contains(pressPoint))
{
qreal tmpXX = pressPoint.x() * 1.0;
if (false == sliderRect.contains(pressPoint))
{
if (tmpXX > (sliderRect.x() + sliderRect.width()))
{
tmpXX = (sliderRect.x() + sliderRect.width() ) * 1.0;
}
else if (tmpXX < sliderRect.x())
{
tmpXX = sliderRect.x() * 1.0;
}
else
{
}
}
m_bPressed = true;
m_dbCurPercent = (tmpXX - sliderRect.x() * 1.0) / sliderRect.width();
m_nCurValue = (m_range.m_nMax - m_range.m_nMin) * m_dbCurPercent;
emit sigValueChanged(m_nCurValue);
update();
}
}
}
}
void LineProgressBar::mouseReleaseEvent(QMouseEvent* event)
{
if (m_bPressed)
{
m_bPressed = false;
}
QWidget::mouseReleaseEvent(event);
}
void LineProgressBar::updateValue(qreal nCurValue)
{
if (m_nCurValue == nCurValue)
{
return;
}
m_nCurValue = nCurValue;
if (m_range.m_nMax == m_range.m_nMin)
m_dbCurPercent = 0;
else
m_dbCurPercent = m_nCurValue * 1.0 / (m_range.m_nMax - m_range.m_nMin);
update();
}
void LineProgressBar::initValue()
{
m_range = { 0, 100 };
m_nCurValue = 0;
m_dbCurPercent = 0;
m_bPressed = false;
}
void LineProgressBar::initUISetting()
{
//setCursor(QCursor(Qt::PointingHandCursor));
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
}