目标
- 基于QWidget自定义网速小部件
- 支持设置上行和下行方向
- 支持自定义设置网速显示数值和单位
- 支持动态设置上行和下行颜色
效果图

控件完整代码
#pragma once
#include <QWidget>
#include <QPainter>
class QPaintEvent;
/// 
/// @brief: 速度仪表控件, 由箭头+文本组成, 并分别在箭头后紧跟文字,箭头朝向分为上下。同时只能显示其中的一种方向(朝上或者朝下)
/// 
class SpeedMeterWidget  : public QWidget
{
	Q_OBJECT
public:
	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/4
	QRectF 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);
}