目标
- 基于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);
}