Qt自定义控件: LED指示灯

1,912 阅读3分钟

背景——在Qt应用程序中,自定义控件可以大大提升用户界面的美观度和交互体验。之前在做的一个东西是要画出指示灯的效果,于是就了解了一下自定义控件、QPainter和QRadialGradient。

设计LED控件

自定义的LED控件继承自QAbstractButton,利用按钮的状态变化进行求换。

class SimpleLed : public QAbstractButton
{
    Q_OBJECT

public:
    enum LEDCOLOR { CUSTOM, RED, GREEN };
    enum LEDSTATES { ON, OFF };

    explicit SimpleLed(QWidget *parent = nullptr, LEDCOLOR color = RED);

    void setStates(LEDSTATES states);

protected:
    void paintEvent(QPaintEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;

private:
    LEDCOLOR mColor;
    LEDSTATES mStates;
    bool mOn;

    void resetStatus();
};

绘制LED效果

LED的绘制主要依赖QPainter和QRadialGradient来实现逼真的光晕效果。

1. 准备绘制环境

void SimpleLed::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    qreal realSize = qMin(width(), height());
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(width()/2, height()/2);
    painter.scale(realSize/1000, realSize/1000);
}

这里我们设置了抗锯齿,将绘制原点移到控件中心,并根据控件实际大小进行缩放。

抗锯齿 (Anti-aliasing)

抗锯齿是一种图形处理技术,用于减少或消除由于显示设备分辨率限制而导致的图形边缘锯齿状现象。抗锯齿的工作原理:

  • 边缘像素混合: 在绘制图形边缘时,抗锯齿技术会计算每个像素被图形覆盖的程度,并据此调整像素的颜色值。
  • 平滑过渡: 通过在边缘像素上应用颜色渐变,创造出更平滑的视觉效果。
  • 亚像素渲染: 在理论上对图形进行更高分辨率的渲染,然后将结果缩小到实际显示分辨率。

2. 绘制LED外壳

    QRadialGradient radialGent(QPointF(-500, -500), 1500, QPointF(-500, -500));
    //构造函数参数:
    //QPointF(-500, -500): 渐变的中心点
    //1500: 渐变的半径
    //QPointF(-500, -500): 渐变的焦点(这里与中心点相同)

    radialGent.setColorAt(0, QColor(224, 224, 224));
    //设置渐变起始点(中心)的颜色为浅灰色

    radialGent.setColorAt(1, QColor(28, 28, 28));
    //设置渐变终点(边缘)的颜色为深灰色

    painter.setBrush(QBrush(radialGent));
    painter.drawEllipse(QPointF(0, 0), 500, 500);

使用径向渐变创建LED的金属外壳效果。通过将渐变的中心点和焦点设置在绘制区域之外 (-500, -500),我们可以创造出一种金属质感的光泽效果,使LED外壳看起来更加立体和真实。

径向渐变 (Radial Gradient)

径向渐变是一种从中心点向外扩散的颜色渐变效果。通过巧妙运用径向渐变就可以在2D平面上创造出逼真的3D效果,结合抗锯齿技术,最终呈现的LED图形会非常平滑和精致,能够大大提升视觉质量。

3. 绘制LED内部

    if (isChecked()) {
        radialGent = QRadialGradient(QPointF(-500, -500), 1500, QPointF(-500, -500));
        radialGent.setColorAt(0, smColorPalette[mColor].on0);
        radialGent.setColorAt(1, smColorPalette[mColor].on1);
    } else {
        radialGent = QRadialGradient(QPointF(500, 500), 1500, QPointF(500, 500));
        radialGent.setColorAt(0, smColorPalette[mColor].off0);
        radialGent.setColorAt(1, smColorPalette[mColor].off1);
    }

    painter.setBrush(QBrush(radialGent));
    painter.drawEllipse(QPoint(0, 0), 400, 400);

根据LED的开关状态,使用不同的颜色渐变来绘制LED的发光效果。

4. 处理状态变化

LED控件的状态变化主要通过setStates方法来控制:

void SimpleLed::setStates(SimpleLed::LEDSTATES states)
{
    switch (states) {
    case ON:
        resetStatus();
        setChecked(true);
        mStates = ON;
        break;
    case OFF:
        resetStatus();
        mStates = OFF;
        break;
    }

    mOn = !mOn;
    update();
}

当状态改变时,更新对应控件的checked状态并触发重绘。

5. 最终效果

09_01_LED.png

总结

通过使用QPainter和QRadialGradient,创建了一个自定义的LED指示灯控件。这个控件不仅视觉效果出色,还支持状态切换和颜色自定义,可以很好地适应各种UI设计需求。

在实际应用中,还可以进一步优化控件的性能,比如使用缓存机制来减少重复绘制的开销,也可以考虑添加动画效果,使状态切换更加平滑自然。