feat:初始化wuhan_QT界面代码
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
#include "alarmbanner.h"
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include "global.h"
|
||||
|
||||
AlarmBanner::AlarmBanner(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setFixedHeight(54);
|
||||
setStyleSheet("background: transparent;");
|
||||
|
||||
QHBoxLayout* lay = new QHBoxLayout(this);
|
||||
lay->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
m_label = new QLabel(this);
|
||||
m_label->setAlignment(Qt::AlignCenter);
|
||||
m_label->setProperty("alert", true);
|
||||
m_label->setStyleSheet("font-size:30px;font-weight:700;");
|
||||
lay->addWidget(m_label);
|
||||
|
||||
hide(); // 默认隐藏
|
||||
}
|
||||
|
||||
void AlarmBanner::showAlarm(const QString& text)
|
||||
{
|
||||
m_label->setText(text);
|
||||
startBlink(m_label, "blink");
|
||||
show();
|
||||
}
|
||||
|
||||
void AlarmBanner::clear()
|
||||
{
|
||||
stopBlink(m_label, "blink");
|
||||
hide();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef ALARMBANNER_H
|
||||
#define ALARMBANNER_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QLabel;
|
||||
|
||||
// ===================== 告警横幅 =====================
|
||||
// 整行红色文字,500ms 闪烁;showAlarm 显示,clear 隐藏
|
||||
class AlarmBanner : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AlarmBanner(QWidget* parent = nullptr);
|
||||
|
||||
void showAlarm(const QString& text);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
QLabel* m_label = nullptr;
|
||||
};
|
||||
|
||||
#endif // ALARMBANNER_H
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "confirmdialog.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
#include "global.h"
|
||||
|
||||
ConfirmDialog::ConfirmDialog(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setModal(true);
|
||||
if (parent) setGeometry(parent->rect());
|
||||
setStyleSheet("background-color: rgba(0,0,0,102);");
|
||||
|
||||
QWidget* panel = new QWidget(this);
|
||||
panel->setObjectName("ConfirmPanel");
|
||||
panel->setFixedSize(560, 260);
|
||||
panel->setStyleSheet(QString(
|
||||
"QWidget#ConfirmPanel{background-color:%1;border:2px solid %2;border-radius:16px;}")
|
||||
.arg(C::PANEL, C::BORDER));
|
||||
|
||||
QVBoxLayout* lay = new QVBoxLayout(panel);
|
||||
lay->setContentsMargins(28, 24, 28, 24);
|
||||
lay->setSpacing(16);
|
||||
|
||||
m_title = new QLabel("", panel);
|
||||
m_title->setStyleSheet(QString("color:%1;font-size:28px;font-weight:700;").arg(C::TEXT));
|
||||
m_title->setAlignment(Qt::AlignCenter);
|
||||
lay->addWidget(m_title);
|
||||
|
||||
m_body = new QLabel("", panel);
|
||||
m_body->setStyleSheet(QString("color:%1;font-size:22px;").arg(C::TEXT));
|
||||
m_body->setAlignment(Qt::AlignCenter);
|
||||
m_body->setWordWrap(true);
|
||||
lay->addWidget(m_body, 1);
|
||||
|
||||
QHBoxLayout* btnLay = new QHBoxLayout();
|
||||
btnLay->addStretch(1);
|
||||
QPushButton* ok = new QPushButton("确认", panel);
|
||||
ok->setProperty("variant", "primary");
|
||||
ok->setFixedSize(160, 72);
|
||||
connect(ok, &QPushButton::clicked, this, &ConfirmDialog::accept);
|
||||
QPushButton* cancel = new QPushButton("取消", panel);
|
||||
cancel->setFixedSize(160, 72);
|
||||
connect(cancel, &QPushButton::clicked, this, &ConfirmDialog::reject);
|
||||
btnLay->addWidget(ok);
|
||||
btnLay->addWidget(cancel);
|
||||
btnLay->addStretch(1);
|
||||
lay->addLayout(btnLay);
|
||||
|
||||
QVBoxLayout* root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(0, 0, 0, 0);
|
||||
root->addStretch(1);
|
||||
root->addWidget(panel, 0, Qt::AlignHCenter);
|
||||
root->addStretch(1);
|
||||
}
|
||||
|
||||
void ConfirmDialog::setTitle(const QString& t) { m_title->setText(t); }
|
||||
void ConfirmDialog::setText(const QString& t) { m_body->setText(t); }
|
||||
|
||||
bool ConfirmDialog::confirm(QWidget* parent, const QString& title, const QString& text)
|
||||
{
|
||||
ConfirmDialog dlg(parent);
|
||||
dlg.setTitle(title);
|
||||
dlg.setText(text);
|
||||
return dlg.exec() == QDialog::Accepted;
|
||||
}
|
||||
|
||||
void ConfirmDialog::toast(QWidget* parent, const QString& text, int ms)
|
||||
{
|
||||
QDialog* d = new QDialog(parent);
|
||||
d->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
|
||||
d->setAttribute(Qt::WA_TranslucentBackground);
|
||||
d->setModal(true);
|
||||
if (parent) d->setGeometry(parent->rect());
|
||||
d->setStyleSheet("background-color: rgba(0,0,0,80);");
|
||||
|
||||
QLabel* lbl = new QLabel(text, d);
|
||||
lbl->setAlignment(Qt::AlignCenter);
|
||||
lbl->setStyleSheet(QString(
|
||||
"background-color:%1;color:%2;font-size:28px;font-weight:700;border:2px solid %3;border-radius:16px;padding:32px 48px;")
|
||||
.arg(C::PANEL, C::SUCCESS, C::BORDER));
|
||||
lbl->adjustSize();
|
||||
|
||||
QVBoxLayout* root = new QVBoxLayout(d);
|
||||
root->addStretch(1);
|
||||
root->addWidget(lbl, 0, Qt::AlignHCenter);
|
||||
root->addStretch(1);
|
||||
|
||||
QTimer::singleShot(ms, d, &QDialog::accept);
|
||||
d->exec();
|
||||
d->deleteLater();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef CONFIRMDIALOG_H
|
||||
#define CONFIRMDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QLabel;
|
||||
|
||||
// ===================== 确认弹窗 =====================
|
||||
// 标题 + 正文 + 确认/取消;另提供 2s 自动消失的轻提示(toast)
|
||||
class ConfirmDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ConfirmDialog(QWidget* parent = nullptr);
|
||||
|
||||
void setTitle(const QString& t);
|
||||
void setText(const QString& t);
|
||||
|
||||
// 模态确认,返回是否“确认”
|
||||
static bool confirm(QWidget* parent, const QString& title, const QString& text);
|
||||
|
||||
// 轻提示:显示 text,ms 毫秒后自动消失(用于“修改成功”等)
|
||||
static void toast(QWidget* parent, const QString& text, int ms = 2000);
|
||||
|
||||
private:
|
||||
QLabel* m_title = nullptr;
|
||||
QLabel* m_body = nullptr;
|
||||
};
|
||||
|
||||
#endif // CONFIRMDIALOG_H
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "datacard.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include "global.h"
|
||||
#include <QStyle>
|
||||
|
||||
DataCard::DataCard(const QString& title, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setProperty("card", true);
|
||||
|
||||
QVBoxLayout* lay = new QVBoxLayout(this);
|
||||
lay->setContentsMargins(16, 0, 16, 14);
|
||||
lay->setSpacing(8);
|
||||
|
||||
// 标题栏(高 44px)
|
||||
m_title = new QLabel(title, this);
|
||||
m_title->setFixedHeight(44);
|
||||
m_title->setProperty("cardTitle", true);
|
||||
m_title->setStyleSheet(QString("color:%1;font-size:24px;font-weight:700;border-bottom:1px solid %2;")
|
||||
.arg(C::TEXT, C::BORDER));
|
||||
lay->addWidget(m_title);
|
||||
|
||||
// 字段行容器
|
||||
lay->addStretch(1);
|
||||
}
|
||||
|
||||
void DataCard::setTitle(const QString& t)
|
||||
{
|
||||
m_title->setText(t);
|
||||
}
|
||||
|
||||
int DataCard::addField(const QString& label, const QString& value, bool big)
|
||||
{
|
||||
int index = m_values.size();
|
||||
|
||||
QHBoxLayout* row = new QHBoxLayout();
|
||||
row->setSpacing(8);
|
||||
|
||||
QLabel* lab = new QLabel(label + ":", this);
|
||||
lab->setProperty("sub", true);
|
||||
lab->setStyleSheet(QString("color:%1;font-size:22px;").arg(C::TEXT_SUB));
|
||||
|
||||
QLabel* val = new QLabel(value, this);
|
||||
val->setStyleSheet(QString("color:%1;%2").arg(C::TEXT,
|
||||
big ? "font-size:64px;font-weight:700;" : "font-size:30px;font-weight:700;"));
|
||||
|
||||
row->addWidget(lab);
|
||||
row->addWidget(val, 1);
|
||||
|
||||
// 插入到标题栏之后(stretch 之前)
|
||||
QVBoxLayout* lay = qobject_cast<QVBoxLayout*>(layout());
|
||||
lay->insertLayout(lay->count() - 1, row);
|
||||
|
||||
m_values.append(val);
|
||||
m_labels.append(label);
|
||||
return index;
|
||||
}
|
||||
|
||||
void DataCard::setField(int index, const QString& value)
|
||||
{
|
||||
if (index < 0 || index >= m_values.size())
|
||||
return;
|
||||
m_values[index]->setText(value);
|
||||
}
|
||||
|
||||
void DataCard::setAlarm(int index, bool on)
|
||||
{
|
||||
if (index < 0 || index >= m_values.size())
|
||||
return;
|
||||
QLabel* val = m_values[index];
|
||||
if (on) {
|
||||
val->setProperty("alert", true);
|
||||
startBlink(val, "blink");
|
||||
} else {
|
||||
stopBlink(val, "blink");
|
||||
val->setProperty("alert", false);
|
||||
val->style()->unpolish(val);
|
||||
val->style()->polish(val);
|
||||
}
|
||||
}
|
||||
|
||||
void DataCard::setHighlight(bool on)
|
||||
{
|
||||
if (on)
|
||||
setStyleSheet(QString("QWidget[card=\"true\"]{background-color:%1;border:3px solid %2;border-radius:12px;}")
|
||||
.arg(C::PANEL, C::PRIMARY));
|
||||
else
|
||||
setStyleSheet(QString());
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef DATACARD_H
|
||||
#define DATACARD_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVector>
|
||||
|
||||
class QLabel;
|
||||
|
||||
// ===================== 数据卡片 =====================
|
||||
// 标题栏 + 若干“标签:值”行;支持指定字段红色闪烁告警
|
||||
class DataCard : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DataCard(const QString& title, QWidget* parent = nullptr);
|
||||
|
||||
void setTitle(const QString& t);
|
||||
int addField(const QString& label, const QString& value = "--", bool big = false);
|
||||
void setField(int index, const QString& value);
|
||||
void setAlarm(int index, bool on);
|
||||
void setHighlight(bool on); // 主色描边突出
|
||||
|
||||
private:
|
||||
QLabel* m_title = nullptr;
|
||||
QVector<QLabel*> m_values;
|
||||
QVector<QString> m_labels;
|
||||
};
|
||||
|
||||
#endif // DATACARD_H
|
||||
@@ -0,0 +1,118 @@
|
||||
#include "faulttable.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QTableWidget>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include "global.h"
|
||||
|
||||
FaultTable::FaultTable(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QVBoxLayout* lay = new QVBoxLayout(this);
|
||||
lay->setContentsMargins(0, 0, 0, 0);
|
||||
lay->setSpacing(10);
|
||||
|
||||
// 分页行(上一页 / 页码 / 下一页)
|
||||
QHBoxLayout* nav = new QHBoxLayout();
|
||||
nav->addStretch(1);
|
||||
|
||||
m_prev = new QPushButton("上一页", this);
|
||||
m_prev->setFixedSize(160, 64);
|
||||
connect(m_prev, &QPushButton::clicked, this, [this]() {
|
||||
if (m_page > 0) { setPage(m_page - 1); emit pageChanged(m_page); }
|
||||
});
|
||||
|
||||
m_pageLabel = new QLabel("1/1", this);
|
||||
m_pageLabel->setAlignment(Qt::AlignCenter);
|
||||
m_pageLabel->setStyleSheet(QString("color:%1;font-size:22px;").arg(C::TEXT));
|
||||
m_pageLabel->setFixedWidth(140);
|
||||
|
||||
m_next = new QPushButton("下一页", this);
|
||||
m_next->setFixedSize(160, 64);
|
||||
connect(m_next, &QPushButton::clicked, this, [this]() {
|
||||
if (m_page < pageCount() - 1) { setPage(m_page + 1); emit pageChanged(m_page); }
|
||||
});
|
||||
|
||||
nav->addWidget(m_prev);
|
||||
nav->addWidget(m_pageLabel);
|
||||
nav->addWidget(m_next);
|
||||
lay->addLayout(nav);
|
||||
|
||||
// 表格
|
||||
m_table = new QTableWidget(this);
|
||||
m_table->setColumnCount(3);
|
||||
m_table->setHorizontalHeaderLabels(QStringList() << "序号" << "故障时间" << "故障名称");
|
||||
m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
m_table->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_table->verticalHeader()->setVisible(false);
|
||||
m_table->setAlternatingRowColors(true);
|
||||
m_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
m_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
|
||||
m_table->setColumnWidth(0, 120);
|
||||
m_table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
|
||||
m_table->verticalHeader()->setDefaultSectionSize(100);
|
||||
m_table->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||
connect(m_table, &QTableWidget::cellClicked, this, [this](int row, int) {
|
||||
int global = m_page * m_pageSize + row;
|
||||
if (global >= 0 && global < m_data.size())
|
||||
emit rowClicked(global);
|
||||
});
|
||||
lay->addWidget(m_table, 1);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void FaultTable::setData(const QVector<FaultRecord>& data)
|
||||
{
|
||||
m_data = data;
|
||||
if (m_page >= pageCount() && pageCount() > 0)
|
||||
m_page = pageCount() - 1;
|
||||
refresh();
|
||||
}
|
||||
|
||||
void FaultTable::setPage(int p)
|
||||
{
|
||||
m_page = qBound(0, p, qMax(0, pageCount() - 1));
|
||||
refresh();
|
||||
}
|
||||
|
||||
int FaultTable::pageCount() const
|
||||
{
|
||||
if (m_data.isEmpty()) return 1;
|
||||
return (m_data.size() + m_pageSize - 1) / m_pageSize;
|
||||
}
|
||||
|
||||
void FaultTable::refresh()
|
||||
{
|
||||
m_table->setRowCount(0);
|
||||
m_table->setRowCount(m_pageSize);
|
||||
|
||||
int start = m_page * m_pageSize;
|
||||
for (int r = 0; r < m_pageSize; ++r) {
|
||||
int idx = start + r;
|
||||
bool has = idx < m_data.size();
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
QTableWidgetItem* it = new QTableWidgetItem();
|
||||
it->setTextAlignment(Qt::AlignCenter);
|
||||
if (has) {
|
||||
const FaultRecord& rec = m_data[idx];
|
||||
if (c == 0) it->setText(QString::number(idx + 1));
|
||||
else if (c == 1) it->setText(rec.time);
|
||||
else it->setText(rec.desc);
|
||||
}
|
||||
m_table->setItem(r, c, it);
|
||||
}
|
||||
}
|
||||
|
||||
// 空数据显示提示
|
||||
if (m_data.isEmpty()) {
|
||||
m_table->clearSelection();
|
||||
}
|
||||
|
||||
m_pageLabel->setText(QString("%1/%2").arg(m_page + 1).arg(pageCount()));
|
||||
m_prev->setEnabled(m_page > 0);
|
||||
m_next->setEnabled(m_page < pageCount() - 1);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef FAULTTABLE_H
|
||||
#define FAULTTABLE_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVector>
|
||||
#include "appcontext.h" // FaultRecord
|
||||
|
||||
class QTableWidget;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
|
||||
// ===================== 故障分页表格 =====================
|
||||
// 表头(序号/故障时间/故障名称)+ 数据行 + 上一页/下一页 + 页码指示,每页 6 行
|
||||
class FaultTable : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FaultTable(QWidget* parent = nullptr);
|
||||
|
||||
void setData(const QVector<FaultRecord>& data);
|
||||
void setPage(int p);
|
||||
int page() const { return m_page; }
|
||||
int pageCount() const;
|
||||
|
||||
signals:
|
||||
void pageChanged(int page);
|
||||
void rowClicked(int globalIndex);
|
||||
|
||||
private:
|
||||
void refresh();
|
||||
|
||||
QTableWidget* m_table = nullptr;
|
||||
QLabel* m_pageLabel = nullptr;
|
||||
QPushButton* m_prev = nullptr;
|
||||
QPushButton* m_next = nullptr;
|
||||
QVector<FaultRecord> m_data;
|
||||
int m_page = 0;
|
||||
int m_pageSize = 6;
|
||||
};
|
||||
|
||||
#endif // FAULTTABLE_H
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "ledindicator.h"
|
||||
#include <QPainter>
|
||||
#include <QRadialGradient>
|
||||
#include "global.h"
|
||||
|
||||
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;
|
||||
bool needBlink = (s == RedBlink || s == YellowBlink);
|
||||
if (needBlink && !m_blink) {
|
||||
m_blink = new QTimer(this);
|
||||
m_blink->setInterval(500);
|
||||
connect(m_blink, &QTimer::timeout, this, [this]() {
|
||||
m_on = !m_on;
|
||||
update();
|
||||
});
|
||||
m_blink->start();
|
||||
m_on = true;
|
||||
} else if (!needBlink && m_blink) {
|
||||
m_blink->stop();
|
||||
delete m_blink;
|
||||
m_blink = nullptr;
|
||||
m_on = true;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void LedIndicator::setText(const QString& t)
|
||||
{
|
||||
m_text = t;
|
||||
update();
|
||||
}
|
||||
|
||||
void LedIndicator::paintEvent(QPaintEvent*)
|
||||
{
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
// 中心圆点颜色
|
||||
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_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);
|
||||
|
||||
// 文字
|
||||
p.setPen(QColor(C::TEXT));
|
||||
QFont f = p.font();
|
||||
f.setPixelSize(24);
|
||||
p.setFont(f);
|
||||
const QRectF textRect(m_radius * 2 + 16, 0, width() - m_radius * 2 - 16, height());
|
||||
p.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, m_text);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef LEDINDICATOR_H
|
||||
#define LEDINDICATOR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
|
||||
// ===================== 指示灯(自绘圆形渐变 + 外发光) =====================
|
||||
// 状态:灰=未运行/关闭/正常,绿=运行/开启/到位,红=故障/液位低,
|
||||
// 黄=检测中;红闪/黄闪按 500ms 周期闪烁(透明度 40%↔100%)。
|
||||
class LedIndicator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum State { Off, Green, Red, RedBlink, Yellow, YellowBlink };
|
||||
|
||||
explicit LedIndicator(const QString& text, QWidget* parent = nullptr);
|
||||
|
||||
void setState(State s);
|
||||
void setText(const QString& t);
|
||||
State state() const { return m_state; }
|
||||
|
||||
QSize sizeHint() const override { return QSize(140, 44); }
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
|
||||
private:
|
||||
State m_state = Off;
|
||||
QString m_text;
|
||||
QTimer* m_blink = nullptr;
|
||||
bool m_on = true;
|
||||
int m_radius = 16; // 圆形指示点 32×32
|
||||
};
|
||||
|
||||
#endif // LEDINDICATOR_H
|
||||
@@ -0,0 +1,139 @@
|
||||
#include "numpaddialog.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include "global.h"
|
||||
|
||||
NumPadDialog::NumPadDialog(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setModal(true);
|
||||
|
||||
// 覆盖整个父窗口,作为半透明遮罩
|
||||
if (parent) setGeometry(parent->rect());
|
||||
setStyleSheet("background-color: rgba(0,0,0,102);");
|
||||
|
||||
// 面板(居中)
|
||||
QWidget* panel = new QWidget(this);
|
||||
panel->setObjectName("NumPadPanel");
|
||||
panel->setFixedSize(960, 486);
|
||||
panel->setStyleSheet(QString(
|
||||
"QWidget#NumPadPanel{background-color:%1;border:2px solid %2;border-radius:16px;}")
|
||||
.arg(C::PANEL, C::BORDER));
|
||||
|
||||
QVBoxLayout* panelLay = new QVBoxLayout(panel);
|
||||
panelLay->setContentsMargins(24, 24, 24, 24);
|
||||
panelLay->setSpacing(16);
|
||||
|
||||
// 输入回显
|
||||
m_echo = new QLineEdit(panel);
|
||||
m_echo->setReadOnly(true);
|
||||
m_echo->setEchoMode(QLineEdit::Password);
|
||||
m_echo->setAlignment(Qt::AlignCenter);
|
||||
m_echo->setFixedHeight(64);
|
||||
panelLay->addWidget(m_echo);
|
||||
|
||||
// 数字键区(1-9, 0, 退格, 清除)
|
||||
QGridLayout* grid = new QGridLayout();
|
||||
grid->setSpacing(10);
|
||||
const QString digits[3][3] = {{"1","2","3"},{"4","5","6"},{"7","8","9"}};
|
||||
for (int r = 0; r < 3; ++r)
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
QPushButton* b = new QPushButton(digits[r][c], panel);
|
||||
b->setProperty("numpad", true);
|
||||
b->setFixedSize(130, 98);
|
||||
connect(b, &QPushButton::clicked, this, [this, d = digits[r][c]](){ onDigit(d); });
|
||||
grid->addWidget(b, r, c);
|
||||
}
|
||||
|
||||
QPushButton* b0 = new QPushButton("0", panel);
|
||||
b0->setProperty("numpad", true);
|
||||
b0->setFixedSize(130, 98);
|
||||
connect(b0, &QPushButton::clicked, this, [this](){ onDigit("0"); });
|
||||
grid->addWidget(b0, 3, 0);
|
||||
|
||||
QPushButton* bBack = new QPushButton("退格", panel);
|
||||
bBack->setProperty("numpad", true);
|
||||
bBack->setStyleSheet("font-size:28px;background-color:#2D3947;color:#E6EDF3;border:1px solid #3D4A59;border-radius:12px;");
|
||||
bBack->setFixedSize(130, 98);
|
||||
connect(bBack, &QPushButton::clicked, this, &NumPadDialog::onBackspace);
|
||||
grid->addWidget(bBack, 3, 1);
|
||||
|
||||
QPushButton* bClear = new QPushButton("清除", panel);
|
||||
bClear->setProperty("numpad", true);
|
||||
bClear->setStyleSheet("font-size:28px;background-color:#2D3947;color:#E6EDF3;border:1px solid #3D4A59;border-radius:12px;");
|
||||
bClear->setFixedSize(130, 98);
|
||||
connect(bClear, &QPushButton::clicked, this, &NumPadDialog::onClear);
|
||||
grid->addWidget(bClear, 3, 2);
|
||||
|
||||
// 确认 / 取消
|
||||
QPushButton* bOk = new QPushButton("确认", panel);
|
||||
bOk->setProperty("variant", "primary");
|
||||
bOk->setFixedSize(130, 98);
|
||||
connect(bOk, &QPushButton::clicked, this, &NumPadDialog::accept);
|
||||
|
||||
QPushButton* bCancel = new QPushButton("取消", panel);
|
||||
bCancel->setFixedSize(130, 98);
|
||||
connect(bCancel, &QPushButton::clicked, this, &NumPadDialog::reject);
|
||||
|
||||
grid->addWidget(bOk, 3, 3);
|
||||
grid->addWidget(bCancel, 3, 4);
|
||||
grid->setColumnStretch(4, 0);
|
||||
grid->setColumnStretch(5, 1);
|
||||
|
||||
panelLay->addLayout(grid);
|
||||
panelLay->addStretch(1);
|
||||
|
||||
// 居中放置面板
|
||||
QVBoxLayout* root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(0, 0, 0, 0);
|
||||
root->addStretch(1);
|
||||
root->addWidget(panel, 0, Qt::AlignHCenter);
|
||||
root->addStretch(1);
|
||||
|
||||
refreshEcho();
|
||||
}
|
||||
|
||||
void NumPadDialog::setValue(const QString& v)
|
||||
{
|
||||
m_value = v.left(m_maxLen);
|
||||
refreshEcho();
|
||||
}
|
||||
|
||||
void NumPadDialog::clear()
|
||||
{
|
||||
m_value.clear();
|
||||
refreshEcho();
|
||||
}
|
||||
|
||||
void NumPadDialog::onDigit(const QString& d)
|
||||
{
|
||||
if (m_value.size() >= m_maxLen)
|
||||
return; // 超过最大位数忽略
|
||||
m_value += d;
|
||||
refreshEcho();
|
||||
}
|
||||
|
||||
void NumPadDialog::onBackspace()
|
||||
{
|
||||
if (!m_value.isEmpty())
|
||||
m_value.chop(1);
|
||||
refreshEcho();
|
||||
}
|
||||
|
||||
void NumPadDialog::onClear()
|
||||
{
|
||||
m_value.clear();
|
||||
refreshEcho();
|
||||
}
|
||||
|
||||
void NumPadDialog::refreshEcho()
|
||||
{
|
||||
m_echo->setText(m_value);
|
||||
m_echo->setCursorPosition(m_value.size());
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef NUMPADDIALOG_H
|
||||
#define NUMPADDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
// ===================== 数字键盘弹窗(模态) =====================
|
||||
// 半透明遮罩 + 键盘面板:顶部输入回显,数字键 1-9、0,退格、清除,确认/取消
|
||||
class NumPadDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NumPadDialog(QWidget* parent = nullptr);
|
||||
|
||||
void setMaxLen(int n) { m_maxLen = n; }
|
||||
void setValue(const QString& v);
|
||||
QString value() const { return m_value; }
|
||||
void clear();
|
||||
|
||||
private slots:
|
||||
void onDigit(const QString& d);
|
||||
void onBackspace();
|
||||
void onClear();
|
||||
|
||||
private:
|
||||
void refreshEcho();
|
||||
|
||||
QLineEdit* m_echo = nullptr;
|
||||
QString m_value;
|
||||
int m_maxLen = 4;
|
||||
};
|
||||
|
||||
#endif // NUMPADDIALOG_H
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "paramcontrol.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include "global.h"
|
||||
|
||||
ParamControl::ParamControl(const QString& name, const QString& unit,
|
||||
double step, double min, double max,
|
||||
bool withSave, bool withFactory, QWidget* parent)
|
||||
: QWidget(parent), m_name(name), m_unit(unit),
|
||||
m_step(step), m_min(min), m_max(max), m_value(min)
|
||||
{
|
||||
QVBoxLayout* lay = new QVBoxLayout(this);
|
||||
lay->setContentsMargins(12, 8, 12, 8);
|
||||
lay->setSpacing(6);
|
||||
|
||||
// 参数名
|
||||
QLabel* nameLabel = new QLabel(name, this);
|
||||
nameLabel->setProperty("sub", true);
|
||||
nameLabel->setStyleSheet(QString("color:%1;font-size:22px;").arg(C::TEXT_SUB));
|
||||
lay->addWidget(nameLabel);
|
||||
|
||||
// 数值 + 加减
|
||||
QHBoxLayout* row = new QHBoxLayout();
|
||||
row->setSpacing(12);
|
||||
|
||||
QPushButton* minus = new QPushButton("-", this);
|
||||
minus->setFixedSize(96, 96);
|
||||
minus->setStyleSheet(QString("font-size:44px;background-color:%1;color:%2;border:1px solid %3;border-radius:12px;")
|
||||
.arg(C::PANEL_HI, C::TEXT, C::BORDER));
|
||||
connect(minus, &QPushButton::clicked, this, &ParamControl::onMinus);
|
||||
|
||||
m_valueLabel = new QLabel(this);
|
||||
m_valueLabel->setAlignment(Qt::AlignCenter);
|
||||
m_valueLabel->setStyleSheet(QString("color:%1;font-size:52px;font-weight:700;").arg(C::TEXT));
|
||||
m_valueLabel->setMinimumWidth(180);
|
||||
|
||||
QPushButton* plus = new QPushButton("+", this);
|
||||
plus->setFixedSize(96, 96);
|
||||
plus->setStyleSheet(QString("font-size:44px;background-color:%1;color:%2;border:1px solid %3;border-radius:12px;")
|
||||
.arg(C::PANEL_HI, C::TEXT, C::BORDER));
|
||||
connect(plus, &QPushButton::clicked, this, &ParamControl::onPlus);
|
||||
|
||||
row->addWidget(minus);
|
||||
row->addWidget(m_valueLabel, 1);
|
||||
row->addWidget(plus);
|
||||
lay->addLayout(row);
|
||||
|
||||
// 保存 / 恢复出厂值(可选)
|
||||
if (withSave || withFactory) {
|
||||
QHBoxLayout* btnRow = new QHBoxLayout();
|
||||
btnRow->setSpacing(12);
|
||||
if (withSave) {
|
||||
m_save = new QPushButton("保存", this);
|
||||
m_save->setProperty("variant", "primary");
|
||||
m_save->setMinimumHeight(56);
|
||||
connect(m_save, &QPushButton::clicked, this, &ParamControl::saveClicked);
|
||||
btnRow->addWidget(m_save);
|
||||
}
|
||||
if (withFactory) {
|
||||
m_factory = new QPushButton("恢复出厂值", this);
|
||||
m_factory->setMinimumHeight(56);
|
||||
connect(m_factory, &QPushButton::clicked, this, &ParamControl::factoryResetClicked);
|
||||
btnRow->addWidget(m_factory);
|
||||
}
|
||||
lay->addLayout(btnRow);
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void ParamControl::setValue(double v)
|
||||
{
|
||||
m_value = qBound(m_min, v, m_max);
|
||||
refresh();
|
||||
}
|
||||
|
||||
void ParamControl::setEnabled(bool enabled)
|
||||
{
|
||||
QWidget::setEnabled(enabled);
|
||||
}
|
||||
|
||||
void ParamControl::onMinus()
|
||||
{
|
||||
m_value = qMax(m_min, m_value - m_step);
|
||||
refresh();
|
||||
emit valueChanged(m_value);
|
||||
}
|
||||
|
||||
void ParamControl::onPlus()
|
||||
{
|
||||
m_value = qMin(m_max, m_value + m_step);
|
||||
refresh();
|
||||
emit valueChanged(m_value);
|
||||
}
|
||||
|
||||
void ParamControl::refresh()
|
||||
{
|
||||
// 单位格式:整数不显示小数
|
||||
QString s;
|
||||
if (m_step < 1.0)
|
||||
s = QString("%1").arg(m_value, 0, 'f', 1);
|
||||
else
|
||||
s = QString("%1").arg(m_value, 0, 'f', 0);
|
||||
m_valueLabel->setText(s + " " + m_unit);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef PARAMCONTROL_H
|
||||
#define PARAMCONTROL_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
|
||||
// ===================== 参数调节控件 =====================
|
||||
// 参数名 + 大数值显示 + 减/加按钮 + 保存按钮(可选)+ 恢复出厂值按钮(可选)
|
||||
class ParamControl : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ParamControl(const QString& name, const QString& unit,
|
||||
double step, double min, double max,
|
||||
bool withSave, bool withFactory, QWidget* parent = nullptr);
|
||||
|
||||
void setValue(double v);
|
||||
double value() const { return m_value; }
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
signals:
|
||||
void valueChanged(double v);
|
||||
void saveClicked();
|
||||
void factoryResetClicked();
|
||||
|
||||
private slots:
|
||||
void onMinus();
|
||||
void onPlus();
|
||||
|
||||
private:
|
||||
void refresh();
|
||||
|
||||
QString m_name;
|
||||
QString m_unit;
|
||||
double m_step;
|
||||
double m_min;
|
||||
double m_max;
|
||||
double m_value;
|
||||
QLabel* m_valueLabel = nullptr;
|
||||
QPushButton* m_save = nullptr;
|
||||
QPushButton* m_factory = nullptr;
|
||||
};
|
||||
|
||||
#endif // PARAMCONTROL_H
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "statusstrip.h"
|
||||
#include "appcontext.h"
|
||||
#include "udpcommunication.h"
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include "global.h"
|
||||
|
||||
StatusStrip::StatusStrip(AppContext* ctx, QWidget* parent)
|
||||
: QWidget(parent), m_ctx(ctx)
|
||||
{
|
||||
setObjectName("StatusStrip");
|
||||
setFixedHeight(94);
|
||||
setStyleSheet(QString("QWidget#StatusStrip{background-color:%1;border-top:1px solid %2;}")
|
||||
.arg(C::PANEL, C::BORDER));
|
||||
|
||||
QHBoxLayout* lay = new QHBoxLayout(this);
|
||||
lay->setContentsMargins(36, 0, 24, 0);
|
||||
lay->setSpacing(48);
|
||||
|
||||
auto makeVal = [this](const QString& label) {
|
||||
QLabel* l = new QLabel(this);
|
||||
l->setStyleSheet(QString("color:%1;font-size:22px;").arg(C::TEXT_SUB));
|
||||
l->setProperty("label", label);
|
||||
return l;
|
||||
};
|
||||
|
||||
m_battery = makeVal("底盘电量");
|
||||
m_voltage = makeVal("底盘电压");
|
||||
m_levelA = makeVal("清水液位");
|
||||
m_levelFoam = makeVal("泡沫液位");
|
||||
|
||||
lay->addWidget(m_battery);
|
||||
lay->addWidget(m_voltage);
|
||||
lay->addWidget(m_levelA);
|
||||
lay->addWidget(m_levelFoam);
|
||||
lay->addStretch(1);
|
||||
|
||||
// 模式徽标(点击可切换行车/机械臂模式,模拟面板机械旋钮)
|
||||
m_mode = new QPushButton("行车模式", this);
|
||||
m_mode->setFixedSize(180, 48);
|
||||
m_mode->setStyleSheet(QString("background-color:%1;color:#FFFFFF;border-radius:8px;font-size:24px;font-weight:700;border:none;")
|
||||
.arg(C::SUCCESS));
|
||||
m_mode->setCursor(Qt::PointingHandCursor);
|
||||
connect(m_mode, &QPushButton::clicked, this, [this]() {
|
||||
Mode next = (m_ctx->mode == Mode::Drive) ? Mode::Arm : Mode::Drive;
|
||||
m_ctx->setMode(next);
|
||||
});
|
||||
lay->addWidget(m_mode);
|
||||
|
||||
// 返回按钮
|
||||
m_back = new QPushButton("返回", this);
|
||||
m_back->setFixedSize(144, 76);
|
||||
connect(m_back, &QPushButton::clicked, this, &StatusStrip::backClicked);
|
||||
lay->addWidget(m_back);
|
||||
|
||||
connect(m_ctx->comm(), &UdpCommunication::telemetryUpdated, this, &StatusStrip::refresh);
|
||||
connect(m_ctx, &AppContext::modeChanged, this, [this](Mode m) {
|
||||
m_mode->setText(m == Mode::Drive ? "行车模式" : "机械臂模式");
|
||||
m_mode->setStyleSheet(QString("background-color:%1;color:#FFFFFF;border-radius:8px;font-size:24px;font-weight:700;")
|
||||
.arg(m == Mode::Drive ? C::SUCCESS : C::WARNING));
|
||||
});
|
||||
refresh();
|
||||
}
|
||||
|
||||
void StatusStrip::setBackVisible(bool visible)
|
||||
{
|
||||
m_back->setVisible(visible);
|
||||
}
|
||||
|
||||
void StatusStrip::setBackEnabled(bool enabled)
|
||||
{
|
||||
m_back->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void StatusStrip::refresh()
|
||||
{
|
||||
const Telemetry& t = m_ctx->telemetry;
|
||||
m_battery->setText(QString("底盘电量:%1%").arg(t.soc));
|
||||
m_voltage->setText(QString("底盘电压:%1V").arg(t.volt, 0, 'f', 0));
|
||||
m_levelA->setText(QString("清水液位:%1L").arg(t.levelA, 0, 'f', 0));
|
||||
m_levelFoam->setText(QString("泡沫液位:%1L").arg(t.levelFoam, 0, 'f', 0));
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef STATUSSTRIP_H
|
||||
#define STATUSSTRIP_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class AppContext;
|
||||
|
||||
// ===================== 底部状态条(高 94px) =====================
|
||||
// 底盘电量、底盘电压、清水液位、泡沫液位 + 模式徽标 + 返回按钮
|
||||
class StatusStrip : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit StatusStrip(AppContext* ctx, QWidget* parent = nullptr);
|
||||
|
||||
void setBackVisible(bool visible);
|
||||
void setBackEnabled(bool enabled);
|
||||
|
||||
signals:
|
||||
void backClicked();
|
||||
|
||||
private slots:
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
AppContext* m_ctx;
|
||||
QLabel* m_battery = nullptr;
|
||||
QLabel* m_voltage = nullptr;
|
||||
QLabel* m_levelA = nullptr;
|
||||
QLabel* m_levelFoam = nullptr;
|
||||
QPushButton* m_mode = nullptr;
|
||||
QPushButton* m_back = nullptr;
|
||||
};
|
||||
|
||||
#endif // STATUSSTRIP_H
|
||||
@@ -0,0 +1,99 @@
|
||||
#include "titlebar.h"
|
||||
#include "ledindicator.h"
|
||||
#include "appcontext.h"
|
||||
#include "udpcommunication.h"
|
||||
#include "confirmdialog.h"
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QTime>
|
||||
#include "global.h"
|
||||
#include <QStyle>
|
||||
|
||||
TitleBar::TitleBar(AppContext* ctx, QWidget* parent)
|
||||
: QWidget(parent), m_ctx(ctx)
|
||||
{
|
||||
setObjectName("TitleBar");
|
||||
setFixedHeight(98);
|
||||
setStyleSheet(QString("QWidget#TitleBar{background-color:%1;border-bottom:1px solid %2;}")
|
||||
.arg(C::PANEL, C::BORDER));
|
||||
|
||||
QHBoxLayout* lay = new QHBoxLayout(this);
|
||||
lay->setContentsMargins(24, 0, 24, 0);
|
||||
lay->setSpacing(20);
|
||||
|
||||
// 通信状态
|
||||
m_comm = new LedIndicator("通信正常", this);
|
||||
m_comm->setState(LedIndicator::Green);
|
||||
lay->addWidget(m_comm);
|
||||
|
||||
// 标题(居中)
|
||||
m_title = new QLabel("", this);
|
||||
m_title->setAlignment(Qt::AlignCenter);
|
||||
m_title->setStyleSheet(QString("color:%1;font-size:40px;font-weight:700;").arg(C::TEXT));
|
||||
lay->addWidget(m_title, 1);
|
||||
|
||||
// 时间
|
||||
m_time = new QLabel("", this);
|
||||
m_time->setStyleSheet(QString("color:%1;font-size:26px;").arg(C::TEXT_SUB));
|
||||
m_time->setAlignment(Qt::AlignCenter);
|
||||
lay->addWidget(m_time);
|
||||
|
||||
// 软急停按钮
|
||||
m_estop = new QPushButton("急停", this);
|
||||
m_estop->setProperty("variant", "estop");
|
||||
m_estop->setFixedSize(130, 64);
|
||||
connect(m_estop, &QPushButton::clicked, this, [this]() {
|
||||
if (m_ctx->estopTriggered) {
|
||||
if (ConfirmDialog::confirm(window(), "急停复位", "确定复位急停并恢复系统?"))
|
||||
m_ctx->resetEstop();
|
||||
} else {
|
||||
m_ctx->triggerEstop();
|
||||
}
|
||||
});
|
||||
lay->addWidget(m_estop);
|
||||
|
||||
// 通信状态刷新
|
||||
connect(m_ctx->comm(), &UdpCommunication::commOkChanged, this, [this](bool ok) {
|
||||
if (ok) { m_comm->setText("通信正常"); m_comm->setState(LedIndicator::Green); }
|
||||
else { m_comm->setText("通信异常"); m_comm->setState(LedIndicator::RedBlink); }
|
||||
});
|
||||
|
||||
// 急停状态刷新
|
||||
connect(m_ctx, &AppContext::estopChanged, this, &TitleBar::updateEstop);
|
||||
updateEstop();
|
||||
|
||||
// 时钟
|
||||
m_clock = new QTimer(this);
|
||||
connect(m_clock, &QTimer::timeout, this, &TitleBar::updateTime);
|
||||
m_clock->start(1000);
|
||||
updateTime();
|
||||
}
|
||||
|
||||
void TitleBar::setTitle(const QString& title)
|
||||
{
|
||||
m_title->setText(title);
|
||||
}
|
||||
|
||||
void TitleBar::setEstopVisible(bool visible)
|
||||
{
|
||||
m_estop->setVisible(visible);
|
||||
}
|
||||
|
||||
void TitleBar::updateEstop()
|
||||
{
|
||||
if (m_ctx->estopTriggered) {
|
||||
m_estop->setText("复位");
|
||||
m_estop->setProperty("variant", "danger");
|
||||
} else {
|
||||
m_estop->setText("急停");
|
||||
m_estop->setProperty("variant", "estop");
|
||||
}
|
||||
m_estop->style()->unpolish(m_estop);
|
||||
m_estop->style()->polish(m_estop);
|
||||
}
|
||||
|
||||
void TitleBar::updateTime()
|
||||
{
|
||||
m_time->setText(QTime::currentTime().toString("HH:mm"));
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef TITLEBAR_H
|
||||
#define TITLEBAR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class AppContext;
|
||||
class LedIndicator;
|
||||
|
||||
// ===================== 顶条组件(高 98px) =====================
|
||||
// 左侧“通信状态:●正常/异常”,中央页面标题,右侧时间 + 软急停按钮
|
||||
class TitleBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TitleBar(AppContext* ctx, QWidget* parent = nullptr);
|
||||
|
||||
void setTitle(const QString& title);
|
||||
void setEstopVisible(bool visible);
|
||||
|
||||
private slots:
|
||||
void updateEstop();
|
||||
void updateTime();
|
||||
|
||||
private:
|
||||
AppContext* m_ctx;
|
||||
LedIndicator* m_comm;
|
||||
QLabel* m_title = nullptr;
|
||||
QLabel* m_time = nullptr;
|
||||
QPushButton* m_estop = nullptr;
|
||||
QTimer* m_clock = nullptr;
|
||||
};
|
||||
|
||||
#endif // TITLEBAR_H
|
||||
Reference in New Issue
Block a user