#include "ledindicator.h" #include #include #include #include "global.h" QSize LedIndicator::sizeHint() const { QFont f = font(); f.setPixelSize(m_textPx); const QFontMetrics fm(f); const int textW = fm.horizontalAdvance(m_text); if (m_dotAfter) return QSize(textW + 10 + m_radius * 2 + 10, 52); // 文字 + 间距 + 圆点区 + 右侧 10px // 宽度 = 文字起点(圆点区 + 左侧 10px) + 文字宽度 + 右侧 10px return QSize(textLeft() + textW + 10, 52); // 高度与构造函数 setFixedHeight(52) 一致 } LedIndicator::LedIndicator(const QString& text, QWidget* parent) : QWidget(parent), m_text(text) { setFixedHeight(52); setAttribute(Qt::WA_TranslucentBackground); } void LedIndicator::setState(State s) { m_state = s; const bool needBlink = (s == RedBlink || s == YellowBlink); if (needBlink && !m_blinkConn) { // 挂全局节拍,而不是本控件自己起定时器:各自起的话相位互不相同, // 同一屏上的几个指示灯(顶部通信状态、底栏、自检结果…)会各闪各的。 m_blinkConn = connect(BlinkBeat::instance(), &BlinkBeat::toggled, this, [this](bool on) { m_on = on; update(); }); m_on = BlinkBeat::instance()->on(); // 立刻对齐当前相位,别等下一拍 } else if (!needBlink && m_blinkConn) { disconnect(m_blinkConn); m_blinkConn = QMetaObject::Connection(); m_on = true; // 停闪=常亮 } update(); } void LedIndicator::setText(const QString& t) { m_text = t; updateGeometry(); // 文字变了,重新按新宽度请求布局 update(); } void LedIndicator::paintEvent(QPaintEvent*) { QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // 文字度量:圆点位置取决于文字宽度(圆点在文字后时) QFont f = p.font(); f.setPixelSize(m_textPx); p.setFont(f); const QFontMetrics fm(f); const int textW = fm.horizontalAdvance(m_text); // 中心圆点颜色 QColor color = QColor(C::DISABLED); // 灰 switch (m_state) { case Green: color = QColor(C::SUCCESS); break; case Red: color = QColor(C::DANGER); break; case Yellow: color = QColor(C::WARNING); break; case RedBlink: color = QColor(C::DANGER); break; case YellowBlink: color = QColor(C::WARNING); break; default: color = QColor(C::DISABLED); break; } // 闪烁:40% 透明度 if ((m_state == RedBlink || m_state == YellowBlink) && !m_on) color.setAlpha(102); const QPointF c(m_dotAfter ? textW + 10 + m_radius : m_radius + 8, height() / 2.0); // 外发光 if (color.alpha() > 0) { QRadialGradient glow(c, m_radius + 8); QColor g = color; g.setAlpha(color.alpha() / 3); QColor g0 = g; g0.setAlpha(0); glow.setColorAt(0.0, g); glow.setColorAt(1.0, g0); p.setPen(Qt::NoPen); p.setBrush(glow); p.drawEllipse(c, m_radius + 8, m_radius + 8); } // 圆形主体(径向渐变) QRadialGradient grad(c + QPointF(-m_radius / 3.0, -m_radius / 3.0), m_radius * 1.6); QColor hi = color.lighter(130); grad.setColorAt(0.0, hi); grad.setColorAt(1.0, color); p.setBrush(grad); p.setPen(QPen(QColor(C::BORDER), 1)); p.drawEllipse(c, m_radius, m_radius); // 文字(圆点在文字后时,文字从控件左边缘开始) QColor textColor = m_textColor.isValid() ? m_textColor : QColor(C::TEXT); // 顶部状态条这类要“整条闪烁”的场合:文字与圆点同步降到 40% 透明度 if (m_blinkText && (m_state == RedBlink || m_state == YellowBlink) && !m_on) textColor.setAlpha(102); p.setPen(textColor); const QRectF textRect(m_dotAfter ? 0 : textLeft(), 0, m_dotAfter ? textW : width() - textLeft() - 10, height()); p.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, m_text); }