Drawing WiFi Signal Strength Icons with QPainter in Qt
This article demonstratse how to create WiFi signal strength icons in Qt applications, similar to those found on mobile devices. These icons visually represent the connection quality between a device and a wireless network, helping users understand their network connectivity and take appropriate actions like repositioning devices or extending router coverage.
Overview
The implementation uses a custom QWidget called WifiIcon to render signal strength indicators. The paintEvent method handles the drawing operations using QPainter, while setStrength allows dynamic updates to the signal display.
Implementation
Header File
#ifndef WIFICONNECTIVITYICON_H
#define WIFICONNECTIVITYICON_H
#include <QWidget>
class WifiConnectivityIcon : public QWidget
{
Q_OBJECT
public:
explicit WifiConnectivityIcon(QWidget *parent = nullptr);
enum SignalLevel {
None = 0,
Weak,
Fair,
Good,
Excellent
};
void updateSignalLevel(SignalLevel level);
protected:
void paintEvent(QPaintEvent *) override;
void renderArcSegment(QPainter *painter, int radius, int startAngle, int spanAngle, int thickness);
private:
SignalLevel currentSignalLevel;
};
#endif // WIFICONNECTIVITYICON_H
Implementation File
#include "wificonnectivityicon.h"
#include <QPainter>
#include <QPainterPath>
WifiConnectivityIcon::WifiConnectivityIcon(QWidget *parent) : QWidget(parent)
{
currentSignalLevel = SignalLevel::None;
}
void WifiConnectivityIcon::paintEvent(QPaintEvent *)
{
QPainter canvas(this);
canvas.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
const qreal widgetWidth = width();
const qreal widgetHeight = height();
const int minDimension = qMin(widgetWidth, widgetHeight);
const qreal baseRadius = minDimension / 9.5;
const qreal maxArcRadius = widgetHeight * 0.85;
const int arcThickness = widgetHeight / 10.5;
const QColor activeColor = Qt::white;
const QColor inactiveColor = QColor(100, 100, 100);
int activeSegments = 0;
switch(currentSignalLevel) {
case Excellent: activeSegments = 4; break;
case Good: activeSegments = 3; break;
case Fair: activeSegments = 2; break;
case Weak: activeSegments = 1; break;
default: activeSegments = 0; break;
}
for (int segment = 1; segment <= 4; ++segment) {
if (segment <= activeSegments && activeSegments > 0) {
canvas.setBrush(activeColor);
canvas.setPen(activeColor);
} else {
canvas.setBrush(inactiveColor);
canvas.setPen(inactiveColor);
}
switch (segment) {
case 1: // Center dot
canvas.drawEllipse(QPointF(widgetWidth * 0.5, widgetHeight * 0.88), baseRadius, baseRadius);
canvas.translate(QPointF(widgetWidth * 0.5, widgetHeight * 0.9));
break;
case 2: // Inner arc
renderArcSegment(&canvas, maxArcRadius * 0.40, 45, 90, arcThickness);
break;
case 3: // Middle arc
renderArcSegment(&canvas, maxArcRadius * 0.70, 45, 90, arcThickness);
break;
case 4: // Outer arc
renderArcSegment(&canvas, maxArcRadius, 45, 90, arcThickness);
break;
}
}
}
void WifiConnectivityIcon::renderArcSegment(QPainter *painter, int radius, int startAngle, int spanAngle, int thickness)
{
QRectF outerBounds(-radius, -radius, radius * 2, radius * 2);
QPainterPath arcPath;
arcPath.arcTo(outerBounds, startAngle, spanAngle);
QPainterPath innerCutout;
innerCutout.addEllipse(outerBounds.adjusted(thickness, thickness, -thickness, -thickness));
arcPath -= innerCutout;
painter->drawPath(arcPath);
}
void WifiConnectivityIcon::updateSignalLevel(SignalLevel level)
{
currentSignalLevel = level;
update();
}
Usage
To use this component, simply instantiate WifiConnectivityIcon in your main window and call updateSignalLevel() whenever the WiFi signal changes. The widget will automatically redraw to reflect the new signal strength.
This basic implementation can be extended with features like real-time updates, animations, or customizable styling based on application requirements.