目标
- 基于QWidget自定义网速小部件
- 支持设置上行和下行方向
- 支持自定义设置网速显示数值和单位
- 支持动态设置上行和下行颜色
效果图
![](https://img2024.cnblogs.com/blog/1630599/202502/1630599-20250214222246415-1790609320.gif)
控件完整代码
#pragma once#include <QWidget>
#include <QPainter>
class QPaintEvent;///
/// @brief: 速度仪表控件, 由箭头+文本组成, 并分别在箭头后紧跟文字,箭头朝向分为上下。同时只能显示其中的一种方向(朝上或者朝下)
///
class SpeedMeterWidget : public QWidget
{Q_OBJECTpublic:enum ARROW_OPTION{/// 箭头方向-向上AO_UP = 1,/// 箭头方向-向下AO_DOWN = 2,};public:explicit SpeedMeterWidget(QWidget *parent = nullptr);virtual ~SpeedMeterWidget();///// ///// @brief: 设置背景色///// @param: const QString & str ///// @ret: void///// //void setBackgroundColor(const QString& str);/// /// @brief: 设置箭头朝向/// @param: const ARROW_OPTION ao /// @ret: void/// void setArrowOption(const ARROW_OPTION ao);/// /// @brief: 设置箭头填充颜色, 颜色,比如 "#FF00FF" /// @param: const QString & str /// @ret: void/// void setArrowFillColor(const QString& str);/// /// @brief: 设置显示的文本/// @param: const QString & text /// @ret: void/// void setSpeedText(const QString& text);/// /// @brief: 设置显示的文本的颜色/// @param: const QString & str, 颜色,比如 "#FF00FF" /// @ret: void/// void setSpeedTextColor(const QString& str);/// /// @brief: 设置显示的文本大小/// @param: const int size /// @ret: void/// void setSpeedTextPointSize(const int size);private:void paintEvent(QPaintEvent* event);/// /// @brief: 绘制箭头/// @param: QPainter & painter /// @ret: void/// void drawArrow(QPainter& painter, const QRectF& contentRect);/// /// @brief: 绘制自定义文字/// @param: QPainter & painter /// @param: const QRectF & contentRect /// @ret: void/// void drawText(QPainter& painter, const QRectF& contentRect);private:struct PainterHelper;///// 背景色//QString m_backgroundColor{"#E8E8EC"};/// 箭头方向ARROW_OPTION m_arrowOption{AO_DOWN};/// 箭头的填充颜色QString m_arrowFillColor{"#2AEBA2"};/// 显示的文字内容QString m_speedText{"777.0kb/s"};/// 显示的文字的颜色QString m_speedTextColor{ "#5D6B99" };/// 文字的大小int m_speedTextPointSize{10};
};
#include "SpeedMeterWidget.h"struct SpeedMeterWidget::PainterHelper
{PainterHelper(QPainter& p) : m_painter(p){m_painter.save();}virtual ~PainterHelper(){m_painter.restore();}private:QPainter& m_painter;
};SpeedMeterWidget::SpeedMeterWidget(QWidget *parent): QWidget(parent)
{setWindowFlags(Qt::FramelessWindowHint);setAttribute(Qt::WA_TranslucentBackground);
}SpeedMeterWidget::~SpeedMeterWidget()
{}
//
/////
///// @brief: setBackgroundColor
///// @param: const QString & str -
///// @ret: void
/////
//void SpeedMeterWidget::setBackgroundColor(const QString& str)
//{
// m_backgroundColor = str;
// update();
//}///
/// @brief: setArrowOption
/// @param: const ARROW_OPTION ao -
/// @ret: void
///
void SpeedMeterWidget::setArrowOption(const ARROW_OPTION ao)
{m_arrowOption = ao;update();
}///
/// @brief: setArrowFillColor
/// @param: const QString & str -
/// @ret: void
///
void SpeedMeterWidget::setArrowFillColor(const QString& str)
{m_arrowFillColor = str;update();
}///
/// @brief: setSpeedText
/// @param: const QString & text -
/// @ret: void
///
void SpeedMeterWidget::setSpeedText(const QString& text)
{m_speedText = text;update();
}///
/// @brief: setSpeedTextColor
/// @param: const QString & str -
/// @ret: void
///
void SpeedMeterWidget::setSpeedTextColor(const QString& str)
{m_speedTextColor = str;update();
}///
/// @brief: setSpeedTextPointSize
/// @param: const int size -
/// @ret: void
///
void SpeedMeterWidget::setSpeedTextPointSize(const int size)
{m_speedTextPointSize = size;update();
}///
/// @brief: paintEvent
/// @param: QPaintEvent * event -
/// @ret: void
///
void SpeedMeterWidget::paintEvent(QPaintEvent* event)
{if (false == isVisible()){return;}QPainter painter(this);painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);qreal ww = width() * 1.0;qreal hh = height() * 1.0;//painter.scale(ww / 200, hh / 200);painter.setPen(Qt::NoPen);/// 绘制背景色//painter.setBrush(QColor(m_backgroundColor));//painter.drawRect(this->rect());const QRectF contentRect = QRectF(0, 1, ww, hh - 2);/// 绘制背景色drawArrow(painter, contentRect);/// 绘制文本drawText(painter, contentRect);}///
/// @brief: drawArrow
/// @param: QPainter & painter -
/// @ret: void
///
void SpeedMeterWidget::drawArrow(QPainter& painter, const QRectF& contentRect)
{PainterHelper ph(painter);painter.setPen(QColor(m_arrowFillColor));painter.setBrush(QColor(m_arrowFillColor));/// 箭头的组成, 三角形 + 矩形。 三角形和矩形的高度各占控件高度的一半/// 箭头的宽度占控件整体宽度的1/4QRectF arrowRect = contentRect;arrowRect.setWidth(contentRect.width() / 4.0);/// 移动到箭头的中间painter.translate(arrowRect.center());qreal ww = arrowRect.width();qreal hh = arrowRect.height();/// 三角形{/// 用于确定箭头朝向, 1.0标识箭头朝上qreal valueFlag = 1.0;if (AO_DOWN == m_arrowOption){valueFlag = -1.0;}QPointF arrTmp[] = {QPointF(-ww / 2 , 0),QPointF(ww / 2, 0),QPointF(0, -hh / 2 * valueFlag)};painter.drawPolygon(arrTmp, 3);}/// 矩形{qreal rectW = ww / 3;qreal rectH = hh / 2;qreal rectY = 0;if (AO_DOWN == m_arrowOption){rectY = -rectH;}/// 矩形与三角形相邻的边长=箭头区域宽度的一半painter.drawRect(-rectW / 2, rectY, rectW, rectH);}
}///
/// @brief: 绘制自定义文字
/// @param: QPainter & painter -
/// @param: const QRectF & contentRect -
/// @ret: void
///
void SpeedMeterWidget::drawText(QPainter& painter, const QRectF& contentRect)
{PainterHelper ph(painter);painter.setPen(QPen(QColor(m_speedTextColor)));painter.setBrush(Qt::NoBrush);QFont fontTmp = painter.font();fontTmp.setPointSize(m_speedTextPointSize);painter.setFont(fontTmp);/// 文字占整个控件的3/4 宽QRectF textRect = contentRect;qreal tmpW = contentRect.width();textRect.setX(contentRect.x() + contentRect.width() / 4.0);textRect.setWidth(tmpW * 3.0 /4.0);painter.drawText(textRect, Qt::AlignCenter, m_speedText);
}