1761 lines
59 KiB
C++
1761 lines
59 KiB
C++
#include "signalmeasurementwidget.h"
|
||
#include "overlaydialogswidget.h"
|
||
#include <QDateTime>
|
||
#include <QFileDialog>
|
||
#include <QApplication>
|
||
#include <QMouseEvent>
|
||
#include <QDebug>
|
||
#include <random>
|
||
#include <cmath>
|
||
|
||
// ============== 样式常量定义 ==============
|
||
|
||
const QString MeasurementModuleBase::CARD_STYLE =
|
||
"QWidget { background: white; border-radius: 8px; }";
|
||
|
||
const QString MeasurementModuleBase::INPUT_STYLE =
|
||
"QLineEdit, QSpinBox, QDoubleSpinBox { "
|
||
"background: white; border: 2px solid #E0E0E0; border-radius: 6px; "
|
||
"padding: 8px 12px; font-size: 14px; color: #263238; }"
|
||
"QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus { border-color: #1976D2; }";
|
||
|
||
const QString MeasurementModuleBase::PRIMARY_BTN_STYLE =
|
||
"QPushButton { background: #1976D2; color: white; border: none; border-radius: 6px; "
|
||
"padding: 8px 16px; font-size: 13px; font-weight: 500; }"
|
||
"QPushButton:hover { background: #1565C0; }"
|
||
"QPushButton:pressed { background: #0D47A1; }"
|
||
"QPushButton:disabled { background: #BDBDBD; }";
|
||
|
||
const QString MeasurementModuleBase::SECONDARY_BTN_STYLE =
|
||
"QPushButton { background: #455A64; color: white; border: none; border-radius: 6px; "
|
||
"padding: 8px 16px; font-size: 12px; font-weight: 500; }"
|
||
"QPushButton:hover { background: #546E7A; }"
|
||
"QPushButton:pressed { background: #37474F; }";
|
||
|
||
const QString MeasurementModuleBase::VALUE_DISPLAY_STYLE =
|
||
"QLabel { background: #ECEFF1; color: #1976D2; border: 2px solid #90CAF9; "
|
||
"border-radius: 6px; padding: 10px 14px; font-size: 18px; font-weight: bold; "
|
||
"font-family: 'Consolas', 'Monaco', monospace; }";
|
||
|
||
const QString MeasurementModuleBase::LABEL_STYLE =
|
||
"QLabel { font-size: 13px; color: #455A64; font-weight: 500; }";
|
||
|
||
const QString MeasurementModuleBase::GROUPBOX_STYLE =
|
||
"QGroupBox { font-size: 14px; font-weight: bold; color: #263238; "
|
||
"border: 2px solid #E0E0E0; border-radius: 8px; margin-top: 10px; padding-top: 14px; }"
|
||
"QGroupBox::title { subcontrol-origin: margin; left: 16px; padding: 0 8px; "
|
||
"background: white; }";
|
||
|
||
// ============== MeasurementModuleBase ==============
|
||
|
||
MeasurementModuleBase::MeasurementModuleBase(const QString &title, QWidget *parent)
|
||
: QWidget(parent), m_title(title)
|
||
{
|
||
m_mainLayout = new QVBoxLayout(this);
|
||
m_mainLayout->setContentsMargins(12, 12, 12, 12);
|
||
m_mainLayout->setSpacing(10);
|
||
|
||
setStyleSheet("background: #FAFAFA;");
|
||
}
|
||
|
||
QLineEdit *MeasurementModuleBase::createStyledInput(const QString &placeholder, int width)
|
||
{
|
||
auto *input = new QLineEdit(this);
|
||
input->setPlaceholderText(placeholder);
|
||
input->setFixedWidth(width > 0 ? width : 100);
|
||
input->setFixedHeight(36);
|
||
input->setStyleSheet(INPUT_STYLE);
|
||
return input;
|
||
}
|
||
|
||
QDoubleSpinBox *MeasurementModuleBase::createStyledSpinBox(double min, double max, int decimals, int width)
|
||
{
|
||
auto *spin = new QDoubleSpinBox(this);
|
||
spin->setRange(min, max);
|
||
spin->setDecimals(decimals);
|
||
spin->setFixedWidth(width > 0 ? width : 100);
|
||
spin->setFixedHeight(36);
|
||
spin->setButtonSymbols(QAbstractSpinBox::NoButtons);
|
||
spin->setStyleSheet(
|
||
"QDoubleSpinBox { background: white; border: 2px solid #E0E0E0; border-radius: 6px; "
|
||
"padding: 6px 12px 6px 12px; font-size: 13px; color: #263238; }"
|
||
"QDoubleSpinBox:focus { border-color: #1976D2; }");
|
||
|
||
// 创建加减按钮
|
||
auto *plusBtn = new QPushButton("+", this);
|
||
plusBtn->setFixedSize(36, 36);
|
||
plusBtn->setStyleSheet(
|
||
"QPushButton { background: #F5F5F5; border: 2px solid #E0E0E0; border-radius: 6px; "
|
||
"font-size: 20px; font-weight: bold; color: #263238; }"
|
||
"QPushButton:hover { background: #E8E8E8; }"
|
||
"QPushButton:pressed { background: #D0D0D0; }");
|
||
connect(plusBtn, &QPushButton::clicked, spin, &QDoubleSpinBox::stepUp);
|
||
|
||
auto *minusBtn = new QPushButton("-", this);
|
||
minusBtn->setFixedSize(36, 36);
|
||
minusBtn->setStyleSheet(
|
||
"QPushButton { background: #F5F5F5; border: 2px solid #E0E0E0; border-radius: 6px; "
|
||
"font-size: 20px; font-weight: bold; color: #263238; }"
|
||
"QPushButton:hover { background: #E8E8E8; }"
|
||
"QPushButton:pressed { background: #D0D0D0; }");
|
||
connect(minusBtn, &QPushButton::clicked, spin, &QDoubleSpinBox::stepDown);
|
||
|
||
// 将按钮存储到SpinBox的动态属性中,以便外部可以访问
|
||
spin->setProperty("plusButton", QVariant::fromValue(plusBtn));
|
||
spin->setProperty("minusButton", QVariant::fromValue(minusBtn));
|
||
|
||
return spin;
|
||
}
|
||
|
||
QComboBox *MeasurementModuleBase::createStyledComboBox(const QStringList &items, int width)
|
||
{
|
||
auto *combo = new QComboBox(this);
|
||
combo->addItems(items);
|
||
combo->setFixedWidth(width > 0 ? width : 120);
|
||
combo->setFixedHeight(36);
|
||
combo->setStyleSheet(
|
||
"QComboBox { background: white; border: 2px solid #E0E0E0; border-radius: 6px; "
|
||
"padding: 6px 12px 6px 12px; font-size: 13px; color: #263238; }"
|
||
"QComboBox:focus { border-color: #1976D2; }"
|
||
"QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: center right; "
|
||
"width: 42px; border-left: 2px solid #E0E0E0; background: #F5F5F5; "
|
||
"border-top-right-radius: 4px; border-bottom-right-radius: 4px; }"
|
||
"QComboBox::drop-down:hover { background: #E8E8E8; }"
|
||
"QComboBox::drop-down:pressed { background: #D0D0D0; }"
|
||
"QComboBox QAbstractItemView { background: white; selection-background-color: #1976D2; "
|
||
"selection-color: white; outline: none; }"
|
||
"QComboBox QAbstractItemView::item { min-height: 42px; padding: 8px 12px; font-size: 13px; }"
|
||
"QComboBox QAbstractItemView::item:hover { background: #E3F2FD; }");
|
||
return combo;
|
||
}
|
||
|
||
QPushButton *MeasurementModuleBase::createPrimaryButton(const QString &text, int width)
|
||
{
|
||
auto *btn = new QPushButton(text, this);
|
||
btn->setFixedSize(width > 0 ? width : 90, 36);
|
||
btn->setCursor(Qt::PointingHandCursor);
|
||
btn->setStyleSheet(PRIMARY_BTN_STYLE);
|
||
return btn;
|
||
}
|
||
|
||
QPushButton *MeasurementModuleBase::createSecondaryButton(const QString &text, int width)
|
||
{
|
||
auto *btn = new QPushButton(text, this);
|
||
btn->setFixedSize(width > 0 ? width : 80, 36);
|
||
btn->setCursor(Qt::PointingHandCursor);
|
||
btn->setStyleSheet(SECONDARY_BTN_STYLE);
|
||
return btn;
|
||
}
|
||
|
||
QLabel *MeasurementModuleBase::createValueDisplay(const QString &value, int width)
|
||
{
|
||
auto *label = new QLabel(value, this);
|
||
label->setFixedSize(width > 0 ? width : 140, 42);
|
||
label->setAlignment(Qt::AlignCenter);
|
||
label->setStyleSheet(VALUE_DISPLAY_STYLE);
|
||
return label;
|
||
}
|
||
|
||
QGroupBox *MeasurementModuleBase::createStyledGroupBox(const QString &title)
|
||
{
|
||
auto *group = new QGroupBox(title, this);
|
||
group->setStyleSheet(GROUPBOX_STYLE);
|
||
return group;
|
||
}
|
||
|
||
QHBoxLayout *MeasurementModuleBase::createLabeledRow(const QString &label, QWidget *widget, const QString &unit)
|
||
{
|
||
auto *row = new QHBoxLayout();
|
||
row->setSpacing(12);
|
||
|
||
auto *lbl = new QLabel(label, this);
|
||
lbl->setFixedWidth(100);
|
||
lbl->setStyleSheet(LABEL_STYLE);
|
||
lbl->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
|
||
lbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||
row->addWidget(lbl, 0, Qt::AlignVCenter);
|
||
|
||
row->addWidget(widget, 0, Qt::AlignVCenter);
|
||
|
||
// 如果是SpinBox,添加+/-按钮
|
||
if (auto *spin = qobject_cast<QDoubleSpinBox *>(widget))
|
||
{
|
||
if (spin->property("minusButton").isValid())
|
||
{
|
||
auto *minusBtn = qvariant_cast<QPushButton *>(spin->property("minusButton"));
|
||
auto *plusBtn = qvariant_cast<QPushButton *>(spin->property("plusButton"));
|
||
if (minusBtn && plusBtn)
|
||
{
|
||
row->addWidget(minusBtn, 0, Qt::AlignVCenter);
|
||
row->addWidget(plusBtn, 0, Qt::AlignVCenter);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!unit.isEmpty())
|
||
{
|
||
auto *unitLbl = new QLabel(unit, this);
|
||
unitLbl->setStyleSheet("font-size: 13px; color: #78909C;");
|
||
unitLbl->setAlignment(Qt::AlignVCenter);
|
||
unitLbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||
row->addWidget(unitLbl, 0, Qt::AlignVCenter);
|
||
}
|
||
|
||
row->addStretch();
|
||
return row;
|
||
}
|
||
|
||
// ============== RTDMeasurementWidget ==============
|
||
|
||
RTDMeasurementWidget::RTDMeasurementWidget(QWidget *parent)
|
||
: MeasurementModuleBase("热电阻测量", parent), m_channelManager(ChannelManager::instance()), m_selectedChannel(ChannelManager::INPUT_CHANNEL_1), m_currentChannel(ChannelManager::INPUT_CHANNEL_1), m_measurementTimer(new QTimer(this)), m_isMeasuring(false), m_currentMode(FOUR_WIRE_MODE), m_currentRTDType(PT100), m_currentResistance(100.0), m_currentTemperature(0.0)
|
||
{
|
||
setupUI();
|
||
|
||
// 连接定时器
|
||
connect(m_measurementTimer, &QTimer::timeout, this, &RTDMeasurementWidget::updateMeasurement);
|
||
m_measurementTimer->setInterval(200); // 每200ms更新
|
||
}
|
||
|
||
RTDMeasurementWidget::~RTDMeasurementWidget()
|
||
{
|
||
if (m_isMeasuring)
|
||
{
|
||
m_measurementTimer->stop();
|
||
m_channelManager->releaseChannel(m_currentChannel);
|
||
}
|
||
}
|
||
|
||
void RTDMeasurementWidget::setupUI()
|
||
{
|
||
// === 通道选择区域 ===
|
||
m_channelSelectionWidget = new QWidget(this);
|
||
m_channelSelectionWidget->setStyleSheet("background: #37474F; border-radius: 6px;");
|
||
auto *channelLayout = new QHBoxLayout(m_channelSelectionWidget);
|
||
channelLayout->setContentsMargins(20, 14, 20, 14);
|
||
channelLayout->setSpacing(28);
|
||
|
||
auto *channelLabel = new QLabel("选择测量通道:", this);
|
||
channelLabel->setStyleSheet("font-weight: bold; color: #FFFFFF; font-size: 14px;");
|
||
channelLabel->setAlignment(Qt::AlignVCenter);
|
||
channelLayout->addWidget(channelLabel);
|
||
|
||
setupChannelSelection();
|
||
channelLayout->addStretch();
|
||
|
||
m_mainLayout->addWidget(m_channelSelectionWidget);
|
||
|
||
// === 测量组 ===
|
||
auto *measureGroup = createStyledGroupBox("热电阻测量");
|
||
auto *measureLayout = new QVBoxLayout(measureGroup);
|
||
measureLayout->setSpacing(12);
|
||
|
||
// 接线方式和传感器类型
|
||
auto *settingsRow = new QHBoxLayout();
|
||
settingsRow->setSpacing(20);
|
||
settingsRow->setAlignment(Qt::AlignVCenter);
|
||
|
||
m_wireTypeCombo = createStyledComboBox({"2线制", "3线制", "4线制"}, 120);
|
||
m_wireTypeCombo->setCurrentIndex(2); // 默认4线制
|
||
connect(m_wireTypeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||
this, &RTDMeasurementWidget::onWireTypeChanged);
|
||
settingsRow->addLayout(createLabeledRow("接线方式", m_wireTypeCombo));
|
||
|
||
m_rtdTypeCombo = createStyledComboBox({"PT100", "PT1000", "CU50", "CU100"}, 120);
|
||
settingsRow->addLayout(createLabeledRow("传感器类型", m_rtdTypeCombo));
|
||
|
||
settingsRow->addStretch();
|
||
measureLayout->addLayout(settingsRow);
|
||
|
||
// 接线图提示
|
||
m_wiringDiagramLabel = new QLabel("接线图: 输入通道1 四线制 (白-红-灰-黑)", this);
|
||
m_wiringDiagramLabel->setStyleSheet("color: #1976D2; font-size: 13px; padding: 8px; "
|
||
"background: #E3F2FD; border-radius: 4px;");
|
||
measureLayout->addWidget(m_wiringDiagramLabel);
|
||
|
||
// 测量值显示
|
||
auto *displayRow = new QHBoxLayout();
|
||
displayRow->setSpacing(12);
|
||
|
||
auto *resBox = new QVBoxLayout();
|
||
auto *resLabel = new QLabel("电阻值 (Ω)", this);
|
||
resLabel->setStyleSheet(LABEL_STYLE);
|
||
resBox->addWidget(resLabel);
|
||
m_resistanceDisplay = createValueDisplay("---", 140);
|
||
resBox->addWidget(m_resistanceDisplay);
|
||
displayRow->addLayout(resBox);
|
||
|
||
auto *tempBox = new QVBoxLayout();
|
||
auto *tempLabel = new QLabel("温度 (°C)", this);
|
||
tempLabel->setStyleSheet(LABEL_STYLE);
|
||
tempBox->addWidget(tempLabel);
|
||
m_temperatureDisplay = createValueDisplay("---", 140);
|
||
tempBox->addWidget(m_temperatureDisplay);
|
||
displayRow->addLayout(tempBox);
|
||
|
||
auto *lineResBox = new QVBoxLayout();
|
||
auto *lineResLabel = new QLabel("线电阻 (Ω)", this);
|
||
lineResLabel->setStyleSheet(LABEL_STYLE);
|
||
lineResBox->addWidget(lineResLabel);
|
||
m_lineResDisplay = createValueDisplay("---", 120);
|
||
lineResBox->addWidget(m_lineResDisplay);
|
||
displayRow->addLayout(lineResBox);
|
||
|
||
displayRow->addStretch();
|
||
measureLayout->addLayout(displayRow);
|
||
|
||
// 通道状态
|
||
m_channelStatusLabel = new QLabel("通道状态: 输入通道1 - 空闲", this);
|
||
m_channelStatusLabel->setStyleSheet("color: #455A64; font-size: 13px;");
|
||
measureLayout->addWidget(m_channelStatusLabel);
|
||
|
||
// 按钮
|
||
auto *btnRow = new QHBoxLayout();
|
||
btnRow->setSpacing(12);
|
||
m_measureBtn = createPrimaryButton("开始测量", 120);
|
||
connect(m_measureBtn, &QPushButton::clicked, this, &RTDMeasurementWidget::onMeasureClicked);
|
||
btnRow->addWidget(m_measureBtn);
|
||
|
||
m_stopBtn = createSecondaryButton("停止测量", 120);
|
||
m_stopBtn->setEnabled(false);
|
||
connect(m_stopBtn, &QPushButton::clicked, this, &RTDMeasurementWidget::onStopClicked);
|
||
btnRow->addWidget(m_stopBtn);
|
||
|
||
btnRow->addStretch();
|
||
measureLayout->addLayout(btnRow);
|
||
|
||
m_mainLayout->addWidget(measureGroup);
|
||
m_mainLayout->addStretch();
|
||
|
||
// 初始化
|
||
updateConnectionModeVisibility();
|
||
}
|
||
|
||
void RTDMeasurementWidget::setupChannelSelection()
|
||
{
|
||
QList<QPair<ChannelManager::ChannelId, QString>> channels = {
|
||
{ChannelManager::INPUT_CHANNEL_1, "输入通道1"},
|
||
{ChannelManager::INPUT_CHANNEL_2, "输入通道2"}};
|
||
|
||
auto *channelLayout = qobject_cast<QHBoxLayout *>(m_channelSelectionWidget->layout());
|
||
|
||
for (const auto &channel : channels)
|
||
{
|
||
ChannelStatusWidget *widget = new ChannelStatusWidget(
|
||
channel.first, channel.second, this, ChannelStatusWidget::OVERVIEW_MODE);
|
||
widget->setFixedSize(88, 48);
|
||
widget->setCursor(Qt::PointingHandCursor);
|
||
|
||
// 安装事件过滤器处理点击
|
||
widget->installEventFilter(this);
|
||
|
||
m_channelWidgets[channel.first] = widget;
|
||
channelLayout->addWidget(widget);
|
||
}
|
||
|
||
updateChannelSelection();
|
||
}
|
||
|
||
void RTDMeasurementWidget::updateChannelSelection()
|
||
{
|
||
for (auto it = m_channelWidgets.begin(); it != m_channelWidgets.end(); ++it)
|
||
{
|
||
ChannelManager::ChannelId channelId = it.key();
|
||
ChannelStatusWidget *widget = it.value();
|
||
|
||
if (channelId == m_selectedChannel)
|
||
{
|
||
widget->setStyleSheet("background-color: #2c3e50; border: 3px solid #1976D2; border-radius: 8px;");
|
||
}
|
||
else
|
||
{
|
||
widget->setStyleSheet("background-color: #34495e; border: 2px solid #2c3e50; border-radius: 8px;");
|
||
}
|
||
widget->update();
|
||
}
|
||
}
|
||
|
||
void RTDMeasurementWidget::onChannelSelected(ChannelManager::ChannelId channelId)
|
||
{
|
||
if (m_isMeasuring)
|
||
{
|
||
OverlayDialog::information(this, "通道切换", "请先停止当前测量再切换通道。");
|
||
return;
|
||
}
|
||
|
||
m_selectedChannel = channelId;
|
||
m_currentChannel = channelId;
|
||
updateChannelSelection();
|
||
updateConnectionModeVisibility();
|
||
|
||
// 更新状态显示
|
||
QString statusText = QString("通道状态: %1 - %2")
|
||
.arg(m_channelManager->getChannelDisplayName(m_currentChannel))
|
||
.arg(m_channelManager->isChannelAvailable(m_currentChannel) ? "空闲" : "占用中");
|
||
m_channelStatusLabel->setText(statusText);
|
||
}
|
||
|
||
void RTDMeasurementWidget::updateConnectionModeVisibility()
|
||
{
|
||
// 输入通道2只支持二线制
|
||
if (m_selectedChannel == ChannelManager::INPUT_CHANNEL_2)
|
||
{
|
||
m_wireTypeCombo->setEnabled(false);
|
||
m_wireTypeCombo->setCurrentIndex(0); // 强制二线制
|
||
m_currentMode = TWO_WIRE_MODE;
|
||
m_wiringDiagramLabel->setText("接线图: 输入通道2 二线制 (白-灰)");
|
||
}
|
||
else
|
||
{
|
||
m_wireTypeCombo->setEnabled(true);
|
||
onWireTypeChanged(m_wireTypeCombo->currentIndex());
|
||
}
|
||
}
|
||
|
||
void RTDMeasurementWidget::onMeasureClicked()
|
||
{
|
||
if (!validateChannelForMode())
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 确定连接类型
|
||
ChannelManager::ConnectionType connectionType;
|
||
switch (m_currentMode)
|
||
{
|
||
case TWO_WIRE_MODE:
|
||
connectionType = ChannelManager::TWO_WIRE;
|
||
break;
|
||
case THREE_WIRE_MODE:
|
||
connectionType = ChannelManager::THREE_WIRE;
|
||
break;
|
||
case FOUR_WIRE_MODE:
|
||
connectionType = ChannelManager::FOUR_WIRE;
|
||
break;
|
||
}
|
||
|
||
QString description = QString("热电阻测量(%1)").arg(m_wireTypeCombo->currentText());
|
||
|
||
if (!m_channelManager->occupyChannel(m_currentChannel,
|
||
ChannelManager::RESISTANCE_MEASUREMENT,
|
||
description, connectionType))
|
||
{
|
||
OverlayDialog::warning(this, "通道占用",
|
||
QString("无法占用%1,通道可能正在被其他功能使用。")
|
||
.arg(m_channelManager->getChannelDisplayName(m_currentChannel)));
|
||
return;
|
||
}
|
||
|
||
m_isMeasuring = true;
|
||
m_measurementTimer->start();
|
||
|
||
m_measureBtn->setEnabled(false);
|
||
m_stopBtn->setEnabled(true);
|
||
m_wireTypeCombo->setEnabled(false);
|
||
|
||
// 更新通道状态显示
|
||
QString statusText = QString("通道状态: 正在测量 (%1)")
|
||
.arg(m_channelManager->getChannelDisplayName(m_currentChannel));
|
||
m_channelStatusLabel->setText(statusText);
|
||
m_channelStatusLabel->setStyleSheet("color: #1976D2; font-size: 13px; font-weight: bold;");
|
||
|
||
// 更新通道widget状态
|
||
if (m_channelWidgets.contains(m_currentChannel))
|
||
{
|
||
m_channelWidgets[m_currentChannel]->updateStatus(
|
||
ChannelManager::RESISTANCE_MEASUREMENT, "测量中");
|
||
}
|
||
}
|
||
|
||
void RTDMeasurementWidget::onStopClicked()
|
||
{
|
||
if (m_isMeasuring)
|
||
{
|
||
m_measurementTimer->stop();
|
||
m_channelManager->releaseChannel(m_currentChannel);
|
||
m_isMeasuring = false;
|
||
|
||
m_measureBtn->setEnabled(true);
|
||
m_stopBtn->setEnabled(false);
|
||
if (m_selectedChannel == ChannelManager::INPUT_CHANNEL_1)
|
||
{
|
||
m_wireTypeCombo->setEnabled(true);
|
||
}
|
||
|
||
QString statusText = QString("通道状态: %1 - 空闲")
|
||
.arg(m_channelManager->getChannelDisplayName(m_currentChannel));
|
||
m_channelStatusLabel->setText(statusText);
|
||
m_channelStatusLabel->setStyleSheet("color: #455A64; font-size: 13px;");
|
||
|
||
if (m_channelWidgets.contains(m_currentChannel))
|
||
{
|
||
m_channelWidgets[m_currentChannel]->updateStatus(ChannelManager::NONE, "");
|
||
}
|
||
}
|
||
}
|
||
|
||
void RTDMeasurementWidget::onWireTypeChanged(int index)
|
||
{
|
||
m_currentMode = static_cast<MeasurementMode>(index);
|
||
m_lineResDisplay->setVisible(index == 2); // 仅4线制显示线电阻
|
||
|
||
QString channelName = m_channelManager->getChannelDisplayName(m_currentChannel);
|
||
QString wiringText;
|
||
switch (index)
|
||
{
|
||
case 0: // 二线制
|
||
wiringText = QString("接线图: %1 二线制 (白-灰)").arg(channelName);
|
||
break;
|
||
case 1: // 三线制
|
||
wiringText = QString("接线图: %1 三线制 (白-红-灰)").arg(channelName);
|
||
break;
|
||
case 2: // 四线制
|
||
wiringText = QString("接线图: %1 四线制 (白-红-灰-黑)").arg(channelName);
|
||
break;
|
||
}
|
||
m_wiringDiagramLabel->setText(wiringText);
|
||
}
|
||
|
||
void RTDMeasurementWidget::updateMeasurement()
|
||
{
|
||
generateSimulatedData();
|
||
|
||
m_resistanceDisplay->setText(QString::number(m_currentResistance, 'f', 3));
|
||
m_temperatureDisplay->setText(QString::number(m_currentTemperature, 'f', 2));
|
||
|
||
if (m_currentMode == FOUR_WIRE_MODE)
|
||
{
|
||
// 模拟线电阻(四线制可以测量)
|
||
static std::random_device rd;
|
||
static std::mt19937 gen(rd());
|
||
std::uniform_real_distribution<> lineResNoise(0.1, 0.3);
|
||
m_lineResDisplay->setText(QString::number(lineResNoise(gen), 'f', 3));
|
||
}
|
||
|
||
emit measurementDataReady(m_currentResistance, m_currentTemperature);
|
||
}
|
||
|
||
void RTDMeasurementWidget::generateSimulatedData()
|
||
{
|
||
// 生成逼真的RTD模拟数据
|
||
static std::random_device rd;
|
||
static std::mt19937 gen(rd());
|
||
static std::uniform_real_distribution<> noise(-0.02, 0.02);
|
||
|
||
// 基础温度缓慢变化
|
||
static double baseTemp = 20.0;
|
||
static int counter = 0;
|
||
|
||
if (counter++ % 50 == 0)
|
||
{
|
||
baseTemp += noise(gen) * 10;
|
||
baseTemp = std::max(-50.0, std::min(200.0, baseTemp));
|
||
}
|
||
|
||
m_currentTemperature = baseTemp + noise(gen);
|
||
|
||
// PT100 温度转电阻计算 (IEC 60751)
|
||
double R0 = 100.0;
|
||
double A = 3.9083e-3;
|
||
double B = -5.775e-7;
|
||
double C = -4.183e-12;
|
||
double T = m_currentTemperature;
|
||
if (T >= 0)
|
||
{
|
||
m_currentResistance = R0 * (1 + A * T + B * T * T);
|
||
}
|
||
else
|
||
{
|
||
m_currentResistance = R0 * (1 + A * T + B * T * T + C * T * T * T * (T - 100));
|
||
}
|
||
|
||
// 根据接线方式添加测量噪声
|
||
double noiseLevel = 0.001;
|
||
switch (m_currentMode)
|
||
{
|
||
case TWO_WIRE_MODE:
|
||
noiseLevel = 0.005; // 二线制噪声最大
|
||
break;
|
||
case THREE_WIRE_MODE:
|
||
noiseLevel = 0.002; // 三线制中等
|
||
break;
|
||
case FOUR_WIRE_MODE:
|
||
noiseLevel = 0.001; // 四线制噪声最小
|
||
break;
|
||
}
|
||
|
||
m_currentResistance += noise(gen) * noiseLevel;
|
||
}
|
||
|
||
double RTDMeasurementWidget::convertResistanceToTemperature(double resistance)
|
||
{
|
||
// PT100简化逆运算
|
||
double R0 = 100.0;
|
||
double A = 3.9083e-3;
|
||
return (resistance - R0) / (R0 * A);
|
||
}
|
||
|
||
bool RTDMeasurementWidget::validateChannelForMode()
|
||
{
|
||
ChannelManager::ConnectionType connectionType;
|
||
switch (m_currentMode)
|
||
{
|
||
case TWO_WIRE_MODE:
|
||
connectionType = ChannelManager::TWO_WIRE;
|
||
break;
|
||
case THREE_WIRE_MODE:
|
||
connectionType = ChannelManager::THREE_WIRE;
|
||
break;
|
||
case FOUR_WIRE_MODE:
|
||
connectionType = ChannelManager::FOUR_WIRE;
|
||
break;
|
||
}
|
||
|
||
if (!m_channelManager->canChannelSupport(m_currentChannel,
|
||
ChannelManager::RESISTANCE_MEASUREMENT,
|
||
connectionType))
|
||
{
|
||
QString message;
|
||
if (m_currentChannel == ChannelManager::INPUT_CHANNEL_2 &&
|
||
(m_currentMode == THREE_WIRE_MODE || m_currentMode == FOUR_WIRE_MODE))
|
||
{
|
||
message = "输入通道2只支持二线制测量,请选择二线制或切换到输入通道1。";
|
||
}
|
||
else
|
||
{
|
||
message = QString("所选通道不支持%1测量。").arg(m_wireTypeCombo->currentText());
|
||
}
|
||
OverlayDialog::warning(this, "通道限制", message);
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool RTDMeasurementWidget::eventFilter(QObject *obj, QEvent *event)
|
||
{
|
||
// 处理通道选择widget的鼠标事件
|
||
for (auto it = m_channelWidgets.begin(); it != m_channelWidgets.end(); ++it)
|
||
{
|
||
if (it.value() == obj && event->type() == QEvent::MouseButtonPress)
|
||
{
|
||
onChannelSelected(it.key());
|
||
return true;
|
||
}
|
||
}
|
||
return MeasurementModuleBase::eventFilter(obj, event);
|
||
}
|
||
|
||
// ============== ThermocoupleMeasurementWidget ==============
|
||
|
||
ThermocoupleMeasurementWidget::ThermocoupleMeasurementWidget(QWidget *parent)
|
||
: MeasurementModuleBase("热电偶测量", parent)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
void ThermocoupleMeasurementWidget::setupUI()
|
||
{
|
||
auto *measureGroup = createStyledGroupBox("热电偶测量");
|
||
auto *measureLayout = new QVBoxLayout(measureGroup);
|
||
measureLayout->setSpacing(16);
|
||
|
||
m_tcTypeCombo = createStyledComboBox({"K型", "J型", "T型", "E型", "S型", "R型", "B型"}, 150);
|
||
measureLayout->addLayout(createLabeledRow("热电偶类型", m_tcTypeCombo));
|
||
|
||
auto *displayRow = new QHBoxLayout();
|
||
displayRow->setSpacing(16);
|
||
|
||
auto *voltBox = new QVBoxLayout();
|
||
voltBox->addWidget(new QLabel("电压 (mV)", this));
|
||
m_voltageDisplay = createValueDisplay("---", 160);
|
||
voltBox->addWidget(m_voltageDisplay);
|
||
displayRow->addLayout(voltBox);
|
||
|
||
auto *tempBox = new QVBoxLayout();
|
||
tempBox->addWidget(new QLabel("温度 (°C)", this));
|
||
m_temperatureDisplay = createValueDisplay("---", 160);
|
||
tempBox->addWidget(m_temperatureDisplay);
|
||
displayRow->addLayout(tempBox);
|
||
|
||
displayRow->addStretch();
|
||
measureLayout->addLayout(displayRow);
|
||
|
||
m_measureBtn = createPrimaryButton("开始测量", 140);
|
||
connect(m_measureBtn, &QPushButton::clicked, this, &ThermocoupleMeasurementWidget::onMeasureClicked);
|
||
measureLayout->addWidget(m_measureBtn);
|
||
|
||
m_mainLayout->addWidget(measureGroup);
|
||
|
||
auto *outputGroup = createStyledGroupBox("热电偶模拟输出");
|
||
auto *outputLayout = new QVBoxLayout(outputGroup);
|
||
outputLayout->setSpacing(16);
|
||
|
||
m_outputTempSpin = createStyledSpinBox(-200, 1300, 1, 150);
|
||
m_outputTempSpin->setValue(100.0);
|
||
outputLayout->addLayout(createLabeledRow("设定温度", m_outputTempSpin, "°C"));
|
||
|
||
auto *outDisplayRow = new QHBoxLayout();
|
||
outDisplayRow->setSpacing(16);
|
||
auto *outVoltLbl = new QLabel("输出电压 (mV):", this);
|
||
outDisplayRow->addWidget(outVoltLbl);
|
||
m_outputVoltageDisplay = createValueDisplay("---", 180);
|
||
outDisplayRow->addWidget(m_outputVoltageDisplay);
|
||
outDisplayRow->addStretch();
|
||
outputLayout->addLayout(outDisplayRow);
|
||
|
||
m_outputBtn = createPrimaryButton("启动输出", 140);
|
||
connect(m_outputBtn, &QPushButton::clicked, this, &ThermocoupleMeasurementWidget::onOutputClicked);
|
||
outputLayout->addWidget(m_outputBtn);
|
||
|
||
m_mainLayout->addWidget(outputGroup);
|
||
m_mainLayout->addStretch();
|
||
}
|
||
|
||
void ThermocoupleMeasurementWidget::onMeasureClicked()
|
||
{
|
||
m_voltageDisplay->setText("4.096");
|
||
m_temperatureDisplay->setText("100.2");
|
||
}
|
||
|
||
void ThermocoupleMeasurementWidget::onOutputClicked()
|
||
{
|
||
double temp = m_outputTempSpin->value();
|
||
// K型热电偶简化: ~40µV/°C
|
||
double voltage = temp * 0.04;
|
||
m_outputVoltageDisplay->setText(QString::number(voltage, 'f', 3));
|
||
OverlayDialog::information(this, "输出启动",
|
||
QString("已启动热电偶输出\n温度: %1°C\n电压: %2mV").arg(temp).arg(voltage, 0, 'f', 3));
|
||
}
|
||
|
||
// ============== InsulationMeasurementWidget ==============
|
||
|
||
InsulationMeasurementWidget::InsulationMeasurementWidget(QWidget *parent)
|
||
: MeasurementModuleBase("绝缘电阻测量", parent)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
void InsulationMeasurementWidget::setupUI()
|
||
{
|
||
auto *measureGroup = createStyledGroupBox("绝缘电阻测量");
|
||
auto *measureLayout = new QVBoxLayout(measureGroup);
|
||
measureLayout->setSpacing(16);
|
||
|
||
auto *voltageRow = new QHBoxLayout();
|
||
auto *voltLbl = new QLabel("测试电压:", this);
|
||
voltLbl->setFixedWidth(100);
|
||
voltLbl->setStyleSheet(LABEL_STYLE);
|
||
voltageRow->addWidget(voltLbl);
|
||
|
||
auto *btnGroup = new QButtonGroup(this);
|
||
m_50vRadio = new QRadioButton("50V", this);
|
||
m_100vRadio = new QRadioButton("100V", this);
|
||
m_50vRadio->setChecked(true);
|
||
btnGroup->addButton(m_50vRadio);
|
||
btnGroup->addButton(m_100vRadio);
|
||
|
||
m_50vRadio->setStyleSheet("QRadioButton { font-size: 14px; spacing: 8px; }");
|
||
m_100vRadio->setStyleSheet("QRadioButton { font-size: 14px; spacing: 8px; }");
|
||
|
||
voltageRow->addWidget(m_50vRadio);
|
||
voltageRow->addWidget(m_100vRadio);
|
||
voltageRow->addStretch();
|
||
measureLayout->addLayout(voltageRow);
|
||
|
||
m_autoTestCheck = new QCheckBox("测量后自动检测绝缘电阻", this);
|
||
m_autoTestCheck->setStyleSheet("QCheckBox { font-size: 14px; color: #455A64; }");
|
||
connect(m_autoTestCheck, &QCheckBox::toggled, this, &InsulationMeasurementWidget::onAutoTestToggled);
|
||
measureLayout->addWidget(m_autoTestCheck);
|
||
|
||
auto *displayBox = new QVBoxLayout();
|
||
displayBox->addWidget(new QLabel("绝缘电阻 (MΩ)", this));
|
||
m_insulationDisplay = createValueDisplay("---", 200);
|
||
displayBox->addWidget(m_insulationDisplay);
|
||
measureLayout->addLayout(displayBox);
|
||
|
||
m_statusDisplay = new QLabel("就绪", this);
|
||
m_statusDisplay->setStyleSheet("font-size: 14px; color: #43A047; font-weight: bold;");
|
||
measureLayout->addWidget(m_statusDisplay);
|
||
|
||
m_dischargeProgress = new QProgressBar(this);
|
||
m_dischargeProgress->setRange(0, 100);
|
||
m_dischargeProgress->setValue(0);
|
||
m_dischargeProgress->setVisible(false);
|
||
m_dischargeProgress->setStyleSheet(
|
||
"QProgressBar { border: 2px solid #E0E0E0; border-radius: 6px; text-align: center; "
|
||
"background: white; height: 28px; }"
|
||
"QProgressBar::chunk { background: #43A047; border-radius: 4px; }");
|
||
measureLayout->addWidget(m_dischargeProgress);
|
||
|
||
m_measureBtn = createPrimaryButton("开始测量", 140);
|
||
connect(m_measureBtn, &QPushButton::clicked, this, &InsulationMeasurementWidget::onMeasureClicked);
|
||
measureLayout->addWidget(m_measureBtn);
|
||
|
||
m_mainLayout->addWidget(measureGroup);
|
||
m_mainLayout->addStretch();
|
||
}
|
||
|
||
void InsulationMeasurementWidget::onMeasureClicked()
|
||
{
|
||
m_statusDisplay->setText("测量中...");
|
||
m_statusDisplay->setStyleSheet("font-size: 14px; color: #1976D2; font-weight: bold;");
|
||
|
||
// 模拟测量
|
||
QTimer::singleShot(1000, this, [this]()
|
||
{
|
||
m_insulationDisplay->setText("125.6");
|
||
m_statusDisplay->setText("测量完成,放电中...");
|
||
m_dischargeProgress->setVisible(true);
|
||
|
||
// 模拟放电过程
|
||
QTimer *timer = new QTimer(this);
|
||
connect(timer, &QTimer::timeout, this, [this, timer]() {
|
||
int val = m_dischargeProgress->value() + 10;
|
||
m_dischargeProgress->setValue(val);
|
||
if (val >= 100) {
|
||
timer->stop();
|
||
timer->deleteLater();
|
||
m_dischargeProgress->setVisible(false);
|
||
m_dischargeProgress->setValue(0);
|
||
m_statusDisplay->setText("就绪");
|
||
m_statusDisplay->setStyleSheet("font-size: 14px; color: #43A047; font-weight: bold;");
|
||
}
|
||
});
|
||
timer->start(200); });
|
||
}
|
||
|
||
void InsulationMeasurementWidget::onAutoTestToggled(bool enabled)
|
||
{
|
||
if (enabled)
|
||
{
|
||
OverlayDialog::information(this, "自动测试", "已启用自动绝缘电阻测试\n将在热电阻/热电偶测量后自动执行");
|
||
}
|
||
}
|
||
|
||
// ============== DCCurrentWidget ==============
|
||
|
||
DCCurrentWidget::DCCurrentWidget(QWidget *parent)
|
||
: MeasurementModuleBase("直流电流", parent)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
void DCCurrentWidget::setupUI()
|
||
{
|
||
auto *measureGroup = createStyledGroupBox("电流测量 (0-20mA)");
|
||
auto *measureLayout = new QVBoxLayout(measureGroup);
|
||
measureLayout->setSpacing(16);
|
||
|
||
auto *displayRow = new QHBoxLayout();
|
||
displayRow->setSpacing(12);
|
||
|
||
auto *currentBox = new QVBoxLayout();
|
||
currentBox->addWidget(new QLabel("当前值 (mA)", this));
|
||
m_currentDisplay = createValueDisplay("---", 140);
|
||
currentBox->addWidget(m_currentDisplay);
|
||
displayRow->addLayout(currentBox);
|
||
|
||
auto *statsBox = new QVBoxLayout();
|
||
statsBox->setSpacing(8);
|
||
|
||
auto *maxRow = new QHBoxLayout();
|
||
maxRow->addWidget(new QLabel("最大:", this));
|
||
m_maxDisplay = new QLabel("---", this);
|
||
m_maxDisplay->setStyleSheet("font-size: 14px; color: #D32F2F; font-weight: bold;");
|
||
maxRow->addWidget(m_maxDisplay);
|
||
maxRow->addStretch();
|
||
statsBox->addLayout(maxRow);
|
||
|
||
auto *minRow = new QHBoxLayout();
|
||
minRow->addWidget(new QLabel("最小:", this));
|
||
m_minDisplay = new QLabel("---", this);
|
||
m_minDisplay->setStyleSheet("font-size: 14px; color: #1976D2; font-weight: bold;");
|
||
minRow->addWidget(m_minDisplay);
|
||
minRow->addStretch();
|
||
statsBox->addLayout(minRow);
|
||
|
||
auto *avgRow = new QHBoxLayout();
|
||
avgRow->addWidget(new QLabel("平均:", this));
|
||
m_avgDisplay = new QLabel("---", this);
|
||
m_avgDisplay->setStyleSheet("font-size: 14px; color: #43A047; font-weight: bold;");
|
||
avgRow->addWidget(m_avgDisplay);
|
||
avgRow->addStretch();
|
||
statsBox->addLayout(avgRow);
|
||
|
||
displayRow->addLayout(statsBox);
|
||
displayRow->addStretch();
|
||
measureLayout->addLayout(displayRow);
|
||
|
||
m_measureBtn = createPrimaryButton("开始测量", 140);
|
||
connect(m_measureBtn, &QPushButton::clicked, this, &DCCurrentWidget::onMeasureClicked);
|
||
measureLayout->addWidget(m_measureBtn);
|
||
|
||
m_mainLayout->addWidget(measureGroup);
|
||
|
||
auto *outputGroup = createStyledGroupBox("电流输出");
|
||
auto *outputLayout = new QVBoxLayout(outputGroup);
|
||
outputLayout->setSpacing(16);
|
||
|
||
auto *modeRow = new QHBoxLayout();
|
||
auto *modeLbl = new QLabel("输出模式:", this);
|
||
modeLbl->setFixedWidth(100);
|
||
modeLbl->setStyleSheet(LABEL_STYLE);
|
||
modeRow->addWidget(modeLbl);
|
||
|
||
auto *modeGroup = new QButtonGroup(this);
|
||
m_activeRadio = new QRadioButton("有源", this);
|
||
m_passiveRadio = new QRadioButton("无源", this);
|
||
m_activeRadio->setChecked(true);
|
||
modeGroup->addButton(m_activeRadio);
|
||
modeGroup->addButton(m_passiveRadio);
|
||
|
||
m_activeRadio->setStyleSheet("QRadioButton { font-size: 14px; }");
|
||
m_passiveRadio->setStyleSheet("QRadioButton { font-size: 14px; }");
|
||
|
||
modeRow->addWidget(m_activeRadio);
|
||
modeRow->addWidget(m_passiveRadio);
|
||
modeRow->addStretch();
|
||
outputLayout->addLayout(modeRow);
|
||
|
||
m_outputSpin = createStyledSpinBox(0, 20, 3, 150);
|
||
m_outputSpin->setValue(4.0);
|
||
outputLayout->addLayout(createLabeledRow("输出电流", m_outputSpin, "mA"));
|
||
|
||
m_outputBtn = createPrimaryButton("启动输出", 140);
|
||
connect(m_outputBtn, &QPushButton::clicked, this, &DCCurrentWidget::onOutputClicked);
|
||
outputLayout->addWidget(m_outputBtn);
|
||
|
||
m_mainLayout->addWidget(outputGroup);
|
||
m_mainLayout->addStretch();
|
||
}
|
||
|
||
void DCCurrentWidget::onMeasureClicked()
|
||
{
|
||
m_currentDisplay->setText("12.456");
|
||
m_maxDisplay->setText("12.502 mA");
|
||
m_minDisplay->setText("12.401 mA");
|
||
m_avgDisplay->setText("12.451 mA");
|
||
}
|
||
|
||
void DCCurrentWidget::onOutputClicked()
|
||
{
|
||
QString mode = m_activeRadio->isChecked() ? "有源" : "无源";
|
||
OverlayDialog::information(this, "输出启动",
|
||
QString("已启动电流输出\n模式: %1\n电流: %2mA").arg(mode).arg(m_outputSpin->value()));
|
||
}
|
||
|
||
// ============== DCVoltageWidget ==============
|
||
|
||
DCVoltageWidget::DCVoltageWidget(QWidget *parent)
|
||
: MeasurementModuleBase("直流电压", parent)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
void DCVoltageWidget::setupUI()
|
||
{
|
||
auto *measureGroup = createStyledGroupBox("电压测量 (0-20V)");
|
||
auto *measureLayout = new QVBoxLayout(measureGroup);
|
||
measureLayout->setSpacing(16);
|
||
|
||
auto *displayRow = new QHBoxLayout();
|
||
displayRow->setSpacing(12);
|
||
|
||
auto *voltBox = new QVBoxLayout();
|
||
voltBox->addWidget(new QLabel("当前值 (V)", this));
|
||
m_voltageDisplay = createValueDisplay("---", 140);
|
||
voltBox->addWidget(m_voltageDisplay);
|
||
displayRow->addLayout(voltBox);
|
||
|
||
auto *statsBox = new QVBoxLayout();
|
||
statsBox->setSpacing(8);
|
||
|
||
auto *maxRow = new QHBoxLayout();
|
||
maxRow->addWidget(new QLabel("最大:", this));
|
||
m_maxDisplay = new QLabel("---", this);
|
||
m_maxDisplay->setStyleSheet("font-size: 14px; color: #D32F2F; font-weight: bold;");
|
||
maxRow->addWidget(m_maxDisplay);
|
||
maxRow->addStretch();
|
||
statsBox->addLayout(maxRow);
|
||
|
||
auto *minRow = new QHBoxLayout();
|
||
minRow->addWidget(new QLabel("最小:", this));
|
||
m_minDisplay = new QLabel("---", this);
|
||
m_minDisplay->setStyleSheet("font-size: 14px; color: #1976D2; font-weight: bold;");
|
||
minRow->addWidget(m_minDisplay);
|
||
minRow->addStretch();
|
||
statsBox->addLayout(minRow);
|
||
|
||
auto *avgRow = new QHBoxLayout();
|
||
avgRow->addWidget(new QLabel("平均:", this));
|
||
m_avgDisplay = new QLabel("---", this);
|
||
m_avgDisplay->setStyleSheet("font-size: 14px; color: #43A047; font-weight: bold;");
|
||
avgRow->addWidget(m_avgDisplay);
|
||
avgRow->addStretch();
|
||
statsBox->addLayout(avgRow);
|
||
|
||
displayRow->addLayout(statsBox);
|
||
displayRow->addStretch();
|
||
measureLayout->addLayout(displayRow);
|
||
|
||
m_measureBtn = createPrimaryButton("开始测量", 140);
|
||
connect(m_measureBtn, &QPushButton::clicked, this, &DCVoltageWidget::onMeasureClicked);
|
||
measureLayout->addWidget(m_measureBtn);
|
||
|
||
m_mainLayout->addWidget(measureGroup);
|
||
|
||
auto *outputGroup = createStyledGroupBox("电压输出");
|
||
auto *outputLayout = new QVBoxLayout(outputGroup);
|
||
outputLayout->setSpacing(16);
|
||
|
||
m_outputSpin = createStyledSpinBox(0, 20, 3, 150);
|
||
m_outputSpin->setValue(5.0);
|
||
outputLayout->addLayout(createLabeledRow("输出电压", m_outputSpin, "V"));
|
||
|
||
m_outputBtn = createPrimaryButton("启动输出", 140);
|
||
connect(m_outputBtn, &QPushButton::clicked, this, &DCVoltageWidget::onOutputClicked);
|
||
outputLayout->addWidget(m_outputBtn);
|
||
|
||
m_mainLayout->addWidget(outputGroup);
|
||
m_mainLayout->addStretch();
|
||
}
|
||
|
||
void DCVoltageWidget::onMeasureClicked()
|
||
{
|
||
m_voltageDisplay->setText("5.123");
|
||
m_maxDisplay->setText("5.156 V");
|
||
m_minDisplay->setText("5.098 V");
|
||
m_avgDisplay->setText("5.124 V");
|
||
}
|
||
|
||
void DCVoltageWidget::onOutputClicked()
|
||
{
|
||
OverlayDialog::information(this, "输出启动",
|
||
QString("已启动电压输出\n电压: %1V").arg(m_outputSpin->value()));
|
||
}
|
||
|
||
// ============== FrequencyWidget ==============
|
||
|
||
FrequencyWidget::FrequencyWidget(QWidget *parent)
|
||
: MeasurementModuleBase("频率信号", parent)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
void FrequencyWidget::setupUI()
|
||
{
|
||
auto *measureGroup = createStyledGroupBox("频率测量");
|
||
auto *measureLayout = new QVBoxLayout(measureGroup);
|
||
measureLayout->setSpacing(16);
|
||
|
||
auto *displayBox = new QVBoxLayout();
|
||
displayBox->addWidget(new QLabel("频率 (Hz)", this));
|
||
m_frequencyDisplay = createValueDisplay("---", 200);
|
||
displayBox->addWidget(m_frequencyDisplay);
|
||
measureLayout->addLayout(displayBox);
|
||
|
||
m_measureBtn = createPrimaryButton("开始测量", 140);
|
||
connect(m_measureBtn, &QPushButton::clicked, this, &FrequencyWidget::onMeasureClicked);
|
||
measureLayout->addWidget(m_measureBtn);
|
||
|
||
m_mainLayout->addWidget(measureGroup);
|
||
|
||
auto *outputGroup = createStyledGroupBox("频率信号输出");
|
||
auto *outputLayout = new QVBoxLayout(outputGroup);
|
||
outputLayout->setSpacing(16);
|
||
|
||
m_waveTypeCombo = createStyledComboBox({"方波", "正弦波"}, 150);
|
||
connect(m_waveTypeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||
this, &FrequencyWidget::onWaveTypeChanged);
|
||
outputLayout->addLayout(createLabeledRow("波形类型", m_waveTypeCombo));
|
||
|
||
m_freqSpin = createStyledSpinBox(0.1, 10000, 1, 150);
|
||
m_freqSpin->setValue(1000.0);
|
||
outputLayout->addLayout(createLabeledRow("频率", m_freqSpin, "Hz"));
|
||
|
||
m_amplitudeSpin = createStyledSpinBox(0.1, 10, 2, 150);
|
||
m_amplitudeSpin->setValue(5.0);
|
||
outputLayout->addLayout(createLabeledRow("幅值", m_amplitudeSpin, "V"));
|
||
|
||
m_outputBtn = createPrimaryButton("启动输出", 140);
|
||
connect(m_outputBtn, &QPushButton::clicked, this, &FrequencyWidget::onOutputClicked);
|
||
outputLayout->addWidget(m_outputBtn);
|
||
|
||
m_mainLayout->addWidget(outputGroup);
|
||
m_mainLayout->addStretch();
|
||
}
|
||
|
||
void FrequencyWidget::onMeasureClicked()
|
||
{
|
||
m_frequencyDisplay->setText("1250.5");
|
||
}
|
||
|
||
void FrequencyWidget::onOutputClicked()
|
||
{
|
||
QString waveType = m_waveTypeCombo->currentText();
|
||
OverlayDialog::information(this, "输出启动",
|
||
QString("已启动频率输出\n波形: %1\n频率: %2Hz\n幅值: %3V")
|
||
.arg(waveType)
|
||
.arg(m_freqSpin->value())
|
||
.arg(m_amplitudeSpin->value()));
|
||
}
|
||
|
||
void FrequencyWidget::onWaveTypeChanged(int)
|
||
{
|
||
// 波形类型变化处理
|
||
}
|
||
|
||
// ============== ACVoltageWidget ==============
|
||
|
||
ACVoltageWidget::ACVoltageWidget(QWidget *parent)
|
||
: MeasurementModuleBase("220VAC测量", parent)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
void ACVoltageWidget::setupUI()
|
||
{
|
||
auto *measureGroup = createStyledGroupBox("交流电压测量");
|
||
auto *measureLayout = new QVBoxLayout(measureGroup);
|
||
measureLayout->setSpacing(16);
|
||
|
||
auto *displayRow = new QHBoxLayout();
|
||
displayRow->setSpacing(16);
|
||
|
||
auto *voltBox = new QVBoxLayout();
|
||
voltBox->addWidget(new QLabel("电压 (V)", this));
|
||
m_voltageDisplay = createValueDisplay("---", 160);
|
||
voltBox->addWidget(m_voltageDisplay);
|
||
displayRow->addLayout(voltBox);
|
||
|
||
auto *freqBox = new QVBoxLayout();
|
||
freqBox->addWidget(new QLabel("频率 (Hz)", this));
|
||
m_frequencyDisplay = createValueDisplay("---", 160);
|
||
freqBox->addWidget(m_frequencyDisplay);
|
||
displayRow->addLayout(freqBox);
|
||
|
||
displayRow->addStretch();
|
||
measureLayout->addLayout(displayRow);
|
||
|
||
m_measureBtn = createPrimaryButton("开始测量", 140);
|
||
connect(m_measureBtn, &QPushButton::clicked, this, &ACVoltageWidget::onMeasureClicked);
|
||
measureLayout->addWidget(m_measureBtn);
|
||
|
||
m_mainLayout->addWidget(measureGroup);
|
||
m_mainLayout->addStretch();
|
||
}
|
||
|
||
void ACVoltageWidget::onMeasureClicked()
|
||
{
|
||
m_voltageDisplay->setText("220.5");
|
||
m_frequencyDisplay->setText("50.0");
|
||
}
|
||
|
||
// ============== SwitchDetectionWidget ==============
|
||
|
||
SwitchDetectionWidget::SwitchDetectionWidget(QWidget *parent)
|
||
: MeasurementModuleBase("开关量检测", parent)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
void SwitchDetectionWidget::setupUI()
|
||
{
|
||
auto *detectGroup = createStyledGroupBox("开关量检测");
|
||
auto *detectLayout = new QVBoxLayout(detectGroup);
|
||
detectLayout->setSpacing(16);
|
||
|
||
auto *modeRow = new QHBoxLayout();
|
||
auto *modeLbl = new QLabel("检测模式:", this);
|
||
modeLbl->setFixedWidth(100);
|
||
modeLbl->setStyleSheet(LABEL_STYLE);
|
||
modeRow->addWidget(modeLbl);
|
||
|
||
auto *modeGroup = new QButtonGroup(this);
|
||
m_resistanceMode = new QRadioButton("电阻通断", this);
|
||
m_voltageMode = new QRadioButton("电压模式 (50V内)", this);
|
||
m_resistanceMode->setChecked(true);
|
||
modeGroup->addButton(m_resistanceMode);
|
||
modeGroup->addButton(m_voltageMode);
|
||
|
||
m_resistanceMode->setStyleSheet("QRadioButton { font-size: 14px; }");
|
||
m_voltageMode->setStyleSheet("QRadioButton { font-size: 14px; }");
|
||
|
||
modeRow->addWidget(m_resistanceMode);
|
||
modeRow->addWidget(m_voltageMode);
|
||
modeRow->addStretch();
|
||
detectLayout->addLayout(modeRow);
|
||
|
||
auto *displayRow = new QHBoxLayout();
|
||
displayRow->setSpacing(16);
|
||
|
||
auto *statusBox = new QVBoxLayout();
|
||
statusBox->addWidget(new QLabel("开关状态", this));
|
||
m_statusDisplay = createValueDisplay("---", 140);
|
||
statusBox->addWidget(m_statusDisplay);
|
||
displayRow->addLayout(statusBox);
|
||
|
||
auto *valueBox = new QVBoxLayout();
|
||
valueBox->addWidget(new QLabel("测量值", this));
|
||
m_valueDisplay = createValueDisplay("---", 160);
|
||
valueBox->addWidget(m_valueDisplay);
|
||
displayRow->addLayout(valueBox);
|
||
|
||
displayRow->addStretch();
|
||
detectLayout->addLayout(displayRow);
|
||
|
||
m_detectBtn = createPrimaryButton("开始检测", 140);
|
||
connect(m_detectBtn, &QPushButton::clicked, this, &SwitchDetectionWidget::onDetectClicked);
|
||
detectLayout->addWidget(m_detectBtn);
|
||
|
||
m_mainLayout->addWidget(detectGroup);
|
||
m_mainLayout->addStretch();
|
||
}
|
||
|
||
void SwitchDetectionWidget::onDetectClicked()
|
||
{
|
||
if (m_resistanceMode->isChecked())
|
||
{
|
||
m_statusDisplay->setText("闭合");
|
||
m_statusDisplay->setStyleSheet(VALUE_DISPLAY_STYLE + " color: #43A047;");
|
||
m_valueDisplay->setText("0.5 Ω");
|
||
}
|
||
else
|
||
{
|
||
m_statusDisplay->setText("断开");
|
||
m_statusDisplay->setStyleSheet(VALUE_DISPLAY_STYLE + " color: #D32F2F;");
|
||
m_valueDisplay->setText("24.5 V");
|
||
}
|
||
}
|
||
|
||
// ============== SignalAcquisitionWidget ==============
|
||
|
||
SignalAcquisitionWidget::SignalAcquisitionWidget(QWidget *parent)
|
||
: MeasurementModuleBase("信号采集", parent)
|
||
{
|
||
setupUI();
|
||
m_acquisitionTimer = new QTimer(this);
|
||
}
|
||
|
||
void SignalAcquisitionWidget::setupUI()
|
||
{
|
||
auto *configGroup = createStyledGroupBox("采集配置");
|
||
auto *configLayout = new QVBoxLayout(configGroup);
|
||
configLayout->setSpacing(16);
|
||
|
||
m_channel1Type = createStyledComboBox({"电压", "电流"}, 120);
|
||
configLayout->addLayout(createLabeledRow("通道1", m_channel1Type));
|
||
|
||
m_channel2Type = createStyledComboBox({"电压", "电流"}, 120);
|
||
configLayout->addLayout(createLabeledRow("通道2", m_channel2Type));
|
||
|
||
m_rateSpin = createStyledSpinBox(25, 1000, 0, 120);
|
||
m_rateSpin->setValue(25);
|
||
m_rateSpin->setSuffix(" ms/点");
|
||
configLayout->addLayout(createLabeledRow("采集速率", m_rateSpin));
|
||
|
||
auto *btnRow = new QHBoxLayout();
|
||
m_startBtn = createPrimaryButton("开始采集", 120);
|
||
m_stopBtn = createSecondaryButton("停止", 100);
|
||
m_exportBtn = createSecondaryButton("导出数据", 120);
|
||
m_stopBtn->setEnabled(false);
|
||
|
||
connect(m_startBtn, &QPushButton::clicked, this, &SignalAcquisitionWidget::onStartClicked);
|
||
connect(m_stopBtn, &QPushButton::clicked, this, &SignalAcquisitionWidget::onStopClicked);
|
||
connect(m_exportBtn, &QPushButton::clicked, this, &SignalAcquisitionWidget::onExportClicked);
|
||
|
||
btnRow->addWidget(m_startBtn);
|
||
btnRow->addWidget(m_stopBtn);
|
||
btnRow->addWidget(m_exportBtn);
|
||
btnRow->addStretch();
|
||
configLayout->addLayout(btnRow);
|
||
|
||
m_mainLayout->addWidget(configGroup);
|
||
|
||
auto *dataGroup = createStyledGroupBox("采集数据");
|
||
auto *dataLayout = new QVBoxLayout(dataGroup);
|
||
|
||
m_dataTable = new QTableWidget(this);
|
||
m_dataTable->setColumnCount(3);
|
||
m_dataTable->setHorizontalHeaderLabels({"时间", "通道1", "通道2"});
|
||
m_dataTable->setStyleSheet(
|
||
"QTableWidget { border: 1px solid #E0E0E0; gridline-color: #E0E0E0; background: white; }"
|
||
"QHeaderView::section { background: #ECEFF1; padding: 8px; border: none; "
|
||
"border-bottom: 2px solid #CFD8DC; font-weight: bold; }");
|
||
m_dataTable->horizontalHeader()->setStretchLastSection(true);
|
||
m_dataTable->setMinimumHeight(250);
|
||
dataLayout->addWidget(m_dataTable);
|
||
|
||
m_mainLayout->addWidget(dataGroup);
|
||
m_mainLayout->addStretch();
|
||
}
|
||
|
||
void SignalAcquisitionWidget::onStartClicked()
|
||
{
|
||
m_startBtn->setEnabled(false);
|
||
m_stopBtn->setEnabled(true);
|
||
m_dataTable->setRowCount(0);
|
||
OverlayDialog::information(this, "采集启动", "信号采集已开始");
|
||
}
|
||
|
||
void SignalAcquisitionWidget::onStopClicked()
|
||
{
|
||
m_startBtn->setEnabled(true);
|
||
m_stopBtn->setEnabled(false);
|
||
OverlayDialog::information(this, "采集停止", "信号采集已停止");
|
||
}
|
||
|
||
void SignalAcquisitionWidget::onExportClicked()
|
||
{
|
||
QString filename = QFileDialog::getSaveFileName(this, "导出数据", "", "CSV文件 (*.csv)");
|
||
if (!filename.isEmpty())
|
||
{
|
||
OverlayDialog::information(this, "导出成功", "数据已导出到: " + filename);
|
||
}
|
||
}
|
||
|
||
// ============== RampSignalWidget ==============
|
||
|
||
RampSignalWidget::RampSignalWidget(QWidget *parent)
|
||
: MeasurementModuleBase("斜波输出", parent)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
void RampSignalWidget::setupUI()
|
||
{
|
||
auto *configGroup = createStyledGroupBox("斜波配置");
|
||
auto *configLayout = new QVBoxLayout(configGroup);
|
||
configLayout->setSpacing(16);
|
||
|
||
m_signalType = createStyledComboBox({"电压", "电流"}, 120);
|
||
configLayout->addLayout(createLabeledRow("信号类型", m_signalType));
|
||
|
||
m_startValue = createStyledSpinBox(0, 20, 3, 120);
|
||
m_startValue->setValue(0);
|
||
configLayout->addLayout(createLabeledRow("起始值", m_startValue));
|
||
|
||
m_endValue = createStyledSpinBox(0, 20, 3, 120);
|
||
m_endValue->setValue(10);
|
||
configLayout->addLayout(createLabeledRow("结束值", m_endValue));
|
||
|
||
m_rampRate = createStyledSpinBox(0.01, 10, 2, 120);
|
||
m_rampRate->setValue(0.1);
|
||
m_rampRate->setSuffix(" /s");
|
||
configLayout->addLayout(createLabeledRow("斜波速率", m_rampRate));
|
||
|
||
auto *displayBox = new QVBoxLayout();
|
||
displayBox->addWidget(new QLabel("当前输出值", this));
|
||
m_currentValueDisplay = createValueDisplay("---", 160);
|
||
displayBox->addWidget(m_currentValueDisplay);
|
||
configLayout->addLayout(displayBox);
|
||
|
||
m_rampProgress = new QProgressBar(this);
|
||
m_rampProgress->setRange(0, 100);
|
||
m_rampProgress->setValue(0);
|
||
m_rampProgress->setStyleSheet(
|
||
"QProgressBar { border: 2px solid #E0E0E0; border-radius: 6px; text-align: center; "
|
||
"background: white; height: 28px; }"
|
||
"QProgressBar::chunk { background: #1976D2; border-radius: 4px; }");
|
||
configLayout->addWidget(m_rampProgress);
|
||
|
||
auto *btnRow = new QHBoxLayout();
|
||
m_startBtn = createPrimaryButton("启动斜波", 120);
|
||
m_stopBtn = createSecondaryButton("停止", 100);
|
||
m_stopBtn->setEnabled(false);
|
||
|
||
connect(m_startBtn, &QPushButton::clicked, this, &RampSignalWidget::onStartClicked);
|
||
connect(m_stopBtn, &QPushButton::clicked, this, &RampSignalWidget::onStopClicked);
|
||
|
||
btnRow->addWidget(m_startBtn);
|
||
btnRow->addWidget(m_stopBtn);
|
||
btnRow->addStretch();
|
||
configLayout->addLayout(btnRow);
|
||
|
||
m_mainLayout->addWidget(configGroup);
|
||
m_mainLayout->addStretch();
|
||
}
|
||
|
||
void RampSignalWidget::onStartClicked()
|
||
{
|
||
m_startBtn->setEnabled(false);
|
||
m_stopBtn->setEnabled(true);
|
||
m_rampProgress->setValue(0);
|
||
m_currentValueDisplay->setText(QString::number(m_startValue->value(), 'f', 3));
|
||
OverlayDialog::information(this, "斜波启动", "斜波信号输出已启动");
|
||
}
|
||
|
||
void RampSignalWidget::onStopClicked()
|
||
{
|
||
m_startBtn->setEnabled(true);
|
||
m_stopBtn->setEnabled(false);
|
||
OverlayDialog::information(this, "斜波停止", "斜波信号输出已停止");
|
||
}
|
||
|
||
// ============== RippleDetectionWidget ==============
|
||
|
||
RippleDetectionWidget::RippleDetectionWidget(QWidget *parent)
|
||
: MeasurementModuleBase("纹波检测", parent)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
void RippleDetectionWidget::setupUI()
|
||
{
|
||
auto *detectGroup = createStyledGroupBox("电源纹波检测 (最大50V)");
|
||
auto *detectLayout = new QVBoxLayout(detectGroup);
|
||
detectLayout->setSpacing(16);
|
||
|
||
auto *displayRow = new QHBoxLayout();
|
||
displayRow->setSpacing(16);
|
||
|
||
auto *rippleBox = new QVBoxLayout();
|
||
rippleBox->addWidget(new QLabel("纹波值 (mVpp)", this));
|
||
m_rippleDisplay = createValueDisplay("---", 160);
|
||
rippleBox->addWidget(m_rippleDisplay);
|
||
displayRow->addLayout(rippleBox);
|
||
|
||
displayRow->addStretch();
|
||
detectLayout->addLayout(displayRow);
|
||
|
||
auto *btnRow = new QHBoxLayout();
|
||
m_detectBtn = createPrimaryButton("检测纹波", 120);
|
||
m_diagnoseBtn = createPrimaryButton("AI诊断", 120);
|
||
m_diagnoseBtn->setEnabled(false);
|
||
|
||
connect(m_detectBtn, &QPushButton::clicked, this, &RippleDetectionWidget::onDetectClicked);
|
||
connect(m_diagnoseBtn, &QPushButton::clicked, this, &RippleDetectionWidget::onDiagnoseClicked);
|
||
|
||
btnRow->addWidget(m_detectBtn);
|
||
btnRow->addWidget(m_diagnoseBtn);
|
||
btnRow->addStretch();
|
||
detectLayout->addLayout(btnRow);
|
||
|
||
m_mainLayout->addWidget(detectGroup);
|
||
|
||
auto *diagGroup = createStyledGroupBox("故障诊断结果");
|
||
auto *diagLayout = new QVBoxLayout(diagGroup);
|
||
diagLayout->setSpacing(12);
|
||
|
||
auto *diagRow = new QHBoxLayout();
|
||
diagRow->addWidget(new QLabel("诊断结果:", this));
|
||
m_diagnosisDisplay = new QLabel("未诊断", this);
|
||
m_diagnosisDisplay->setStyleSheet("font-size: 15px; color: #455A64; font-weight: bold;");
|
||
diagRow->addWidget(m_diagnosisDisplay);
|
||
diagRow->addStretch();
|
||
diagLayout->addLayout(diagRow);
|
||
|
||
auto *confRow = new QHBoxLayout();
|
||
confRow->addWidget(new QLabel("置信度:", this));
|
||
m_confidenceDisplay = new QLabel("---", this);
|
||
m_confidenceDisplay->setStyleSheet("font-size: 15px; color: #1976D2; font-weight: bold;");
|
||
confRow->addWidget(m_confidenceDisplay);
|
||
confRow->addStretch();
|
||
diagLayout->addLayout(confRow);
|
||
|
||
m_mainLayout->addWidget(diagGroup);
|
||
m_mainLayout->addStretch();
|
||
}
|
||
|
||
void RippleDetectionWidget::onDetectClicked()
|
||
{
|
||
m_rippleDisplay->setText("125.6");
|
||
m_diagnoseBtn->setEnabled(true);
|
||
OverlayDialog::information(this, "检测完成", "纹波检测完成,可进行AI诊断");
|
||
}
|
||
|
||
void RippleDetectionWidget::onDiagnoseClicked()
|
||
{
|
||
m_diagnosisDisplay->setText("⚠ 滤波电容老化");
|
||
m_diagnosisDisplay->setStyleSheet("font-size: 15px; color: #F57C00; font-weight: bold;");
|
||
m_confidenceDisplay->setText("92.5%");
|
||
OverlayDialog::warning(this, "诊断完成",
|
||
"AI诊断结果:\n滤波电容老化\n置信度: 92.5%\n\n建议: 更换输出滤波电容");
|
||
}
|
||
|
||
// ============== SignalMeasurementWidget ==============
|
||
|
||
SignalMeasurementWidget::SignalMeasurementWidget(QWidget *parent)
|
||
: QWidget(parent), m_titleLabel(nullptr), m_currentModuleIndex(-1)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
void SignalMeasurementWidget::setModule(int moduleIndex)
|
||
{
|
||
onModuleSelected(moduleIndex);
|
||
}
|
||
|
||
void SignalMeasurementWidget::setupUI()
|
||
{
|
||
auto *mainLayout = new QVBoxLayout(this);
|
||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||
mainLayout->setSpacing(0);
|
||
|
||
// 顶部工具栏
|
||
auto *headerWidget = new QWidget(this);
|
||
headerWidget->setStyleSheet("background: #263238;");
|
||
headerWidget->setFixedHeight(48);
|
||
|
||
auto *headerLayout = new QHBoxLayout(headerWidget);
|
||
headerLayout->setContentsMargins(8, 0, 16, 0);
|
||
headerLayout->setSpacing(12);
|
||
|
||
auto *backBtn = new QPushButton("返回", this);
|
||
backBtn->setFixedHeight(34);
|
||
backBtn->setStyleSheet(
|
||
"QPushButton { background: #455A64; color: white; border: none; border-radius: 4px; "
|
||
"padding: 0 14px; font-size: 13px; }"
|
||
"QPushButton:hover { background: #546E7A; }"
|
||
"QPushButton:pressed { background: #37474F; }");
|
||
connect(backBtn, &QPushButton::clicked, this, &SignalMeasurementWidget::onBackClicked);
|
||
headerLayout->addWidget(backBtn);
|
||
|
||
m_titleLabel = new QLabel("信号测量功能", this);
|
||
m_titleLabel->setStyleSheet("color: white; font-size: 16px; font-weight: bold;");
|
||
headerLayout->addWidget(m_titleLabel, 1);
|
||
|
||
mainLayout->addWidget(headerWidget);
|
||
|
||
// 内容区域 - 添加滚动支持
|
||
setupContentArea();
|
||
|
||
auto *scrollArea = new QScrollArea(this);
|
||
scrollArea->setWidget(m_contentStack);
|
||
scrollArea->setWidgetResizable(true);
|
||
scrollArea->setFrameShape(QFrame::NoFrame);
|
||
scrollArea->setStyleSheet(
|
||
"QScrollArea { background: #FAFAFA; border: none; }"
|
||
"QScrollBar:vertical { width: 8px; background: transparent; }"
|
||
"QScrollBar::handle:vertical { background: #BDBDBD; border-radius: 4px; min-height: 30px; }"
|
||
"QScrollBar::handle:vertical:hover { background: #9E9E9E; }"
|
||
"QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0px; }"
|
||
"QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: transparent; }");
|
||
|
||
mainLayout->addWidget(scrollArea, 1);
|
||
}
|
||
|
||
void SignalMeasurementWidget::setupContentArea()
|
||
{
|
||
m_contentStack = new QStackedWidget(this);
|
||
|
||
m_rtdWidget = new RTDMeasurementWidget(this);
|
||
m_tcWidget = new ThermocoupleMeasurementWidget(this);
|
||
m_insulationWidget = new InsulationMeasurementWidget(this);
|
||
m_dcCurrentWidget = new DCCurrentWidget(this);
|
||
m_dcVoltageWidget = new DCVoltageWidget(this);
|
||
m_frequencyWidget = new FrequencyWidget(this);
|
||
m_acVoltageWidget = new ACVoltageWidget(this);
|
||
m_switchWidget = new SwitchDetectionWidget(this);
|
||
m_acquisitionWidget = new SignalAcquisitionWidget(this);
|
||
m_rampWidget = new RampSignalWidget(this);
|
||
m_rippleWidget = new RippleDetectionWidget(this);
|
||
m_rtdOutputWidget = new RTDOutputWidget(this);
|
||
|
||
m_contentStack->addWidget(m_rtdWidget);
|
||
m_contentStack->addWidget(m_tcWidget);
|
||
m_contentStack->addWidget(m_insulationWidget);
|
||
m_contentStack->addWidget(m_dcCurrentWidget);
|
||
m_contentStack->addWidget(m_dcVoltageWidget);
|
||
m_contentStack->addWidget(m_frequencyWidget);
|
||
m_contentStack->addWidget(m_acVoltageWidget);
|
||
m_contentStack->addWidget(m_switchWidget);
|
||
m_contentStack->addWidget(m_acquisitionWidget);
|
||
m_contentStack->addWidget(m_rampWidget);
|
||
m_contentStack->addWidget(m_rippleWidget);
|
||
m_contentStack->addWidget(m_rtdOutputWidget);
|
||
}
|
||
|
||
void SignalMeasurementWidget::onBackClicked()
|
||
{
|
||
emit backRequested();
|
||
}
|
||
|
||
void SignalMeasurementWidget::onModuleSelected(int index)
|
||
{
|
||
QStringList moduleTitles = {
|
||
"热电阻测量", "热电偶测量", "绝缘电阻测量",
|
||
"直流电流测量", "直流电压测量", "频率信号测量",
|
||
"220VAC测量", "开关量检测", "信号采集",
|
||
"斜波信号输出", "纹波检测诊断", "PT100模拟输出"};
|
||
|
||
m_currentModuleIndex = index;
|
||
if (index >= 0 && index < moduleTitles.size())
|
||
{
|
||
m_titleLabel->setText(moduleTitles[index]);
|
||
m_contentStack->setCurrentIndex(index);
|
||
}
|
||
}
|
||
|
||
// ============== RTDOutputWidget ==============
|
||
|
||
RTDOutputWidget::RTDOutputWidget(QWidget *parent)
|
||
: MeasurementModuleBase("PT100模拟输出", parent),
|
||
m_isChannel1Outputting(false),
|
||
m_isChannel2Outputting(false)
|
||
{
|
||
setupUI();
|
||
}
|
||
|
||
RTDOutputWidget::~RTDOutputWidget()
|
||
{
|
||
}
|
||
|
||
void RTDOutputWidget::setupUI()
|
||
{
|
||
// === 通道1输出组 ===
|
||
auto *channel1Group = createStyledGroupBox("PT100 模拟输出 (输出通道1)");
|
||
auto *ch1Layout = new QVBoxLayout(channel1Group);
|
||
ch1Layout->setSpacing(16);
|
||
|
||
m_channel1TempSpin = createStyledSpinBox(-200, 850, 1, 150);
|
||
m_channel1TempSpin->setValue(25.0);
|
||
connect(m_channel1TempSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
||
this, &RTDOutputWidget::onChannel1TempChanged);
|
||
ch1Layout->addLayout(createLabeledRow("设定温度", m_channel1TempSpin, "°C"));
|
||
|
||
auto *ch1DisplayRow = new QHBoxLayout();
|
||
ch1DisplayRow->setSpacing(16);
|
||
auto *ch1ResLbl = new QLabel("输出电阻 (Ω):", this);
|
||
ch1ResLbl->setStyleSheet(LABEL_STYLE);
|
||
ch1DisplayRow->addWidget(ch1ResLbl);
|
||
m_channel1ResDisplay = createValueDisplay("---", 180);
|
||
ch1DisplayRow->addWidget(m_channel1ResDisplay);
|
||
ch1DisplayRow->addStretch();
|
||
ch1Layout->addLayout(ch1DisplayRow);
|
||
|
||
auto *ch1BtnRow = new QHBoxLayout();
|
||
m_channel1OutputBtn = createPrimaryButton("启动输出", 120);
|
||
connect(m_channel1OutputBtn, &QPushButton::clicked, this, &RTDOutputWidget::onChannel1OutputClicked);
|
||
ch1BtnRow->addWidget(m_channel1OutputBtn);
|
||
|
||
m_channel1StopBtn = createSecondaryButton("停止输出", 120);
|
||
m_channel1StopBtn->setEnabled(false);
|
||
connect(m_channel1StopBtn, &QPushButton::clicked, this, &RTDOutputWidget::onChannel1StopClicked);
|
||
ch1BtnRow->addWidget(m_channel1StopBtn);
|
||
|
||
ch1BtnRow->addStretch();
|
||
ch1Layout->addLayout(ch1BtnRow);
|
||
|
||
m_mainLayout->addWidget(channel1Group);
|
||
|
||
// === 通道2输出组 ===
|
||
auto *channel2Group = createStyledGroupBox("PT100 模拟输出 (输出通道2)");
|
||
auto *ch2Layout = new QVBoxLayout(channel2Group);
|
||
ch2Layout->setSpacing(16);
|
||
|
||
m_channel2TempSpin = createStyledSpinBox(-200, 850, 1, 150);
|
||
m_channel2TempSpin->setValue(25.0);
|
||
connect(m_channel2TempSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
||
this, &RTDOutputWidget::onChannel2TempChanged);
|
||
ch2Layout->addLayout(createLabeledRow("设定温度", m_channel2TempSpin, "°C"));
|
||
|
||
auto *ch2DisplayRow = new QHBoxLayout();
|
||
ch2DisplayRow->setSpacing(16);
|
||
auto *ch2ResLbl = new QLabel("输出电阻 (Ω):", this);
|
||
ch2ResLbl->setStyleSheet(LABEL_STYLE);
|
||
ch2DisplayRow->addWidget(ch2ResLbl);
|
||
m_channel2ResDisplay = createValueDisplay("---", 180);
|
||
ch2DisplayRow->addWidget(m_channel2ResDisplay);
|
||
ch2DisplayRow->addStretch();
|
||
ch2Layout->addLayout(ch2DisplayRow);
|
||
|
||
auto *ch2BtnRow = new QHBoxLayout();
|
||
m_channel2OutputBtn = createPrimaryButton("启动输出", 120);
|
||
connect(m_channel2OutputBtn, &QPushButton::clicked, this, &RTDOutputWidget::onChannel2OutputClicked);
|
||
ch2BtnRow->addWidget(m_channel2OutputBtn);
|
||
|
||
m_channel2StopBtn = createSecondaryButton("停止输出", 120);
|
||
m_channel2StopBtn->setEnabled(false);
|
||
connect(m_channel2StopBtn, &QPushButton::clicked, this, &RTDOutputWidget::onChannel2StopClicked);
|
||
ch2BtnRow->addWidget(m_channel2StopBtn);
|
||
|
||
ch2BtnRow->addStretch();
|
||
ch2Layout->addLayout(ch2BtnRow);
|
||
|
||
m_mainLayout->addWidget(channel2Group);
|
||
m_mainLayout->addStretch();
|
||
|
||
// 初始化显示
|
||
onChannel1TempChanged(m_channel1TempSpin->value());
|
||
onChannel2TempChanged(m_channel2TempSpin->value());
|
||
}
|
||
|
||
void RTDOutputWidget::onChannel1OutputClicked()
|
||
{
|
||
m_isChannel1Outputting = true;
|
||
m_channel1OutputBtn->setEnabled(false);
|
||
m_channel1StopBtn->setEnabled(true);
|
||
m_channel1TempSpin->setEnabled(false);
|
||
|
||
// TODO: 实际发送输出命令到硬件
|
||
qDebug() << "通道1开始输出:" << m_channel1TempSpin->value() << "°C";
|
||
}
|
||
|
||
void RTDOutputWidget::onChannel1StopClicked()
|
||
{
|
||
m_isChannel1Outputting = false;
|
||
m_channel1OutputBtn->setEnabled(true);
|
||
m_channel1StopBtn->setEnabled(false);
|
||
m_channel1TempSpin->setEnabled(true);
|
||
|
||
// TODO: 发送停止输出命令到硬件
|
||
qDebug() << "通道1停止输出";
|
||
}
|
||
|
||
void RTDOutputWidget::onChannel2OutputClicked()
|
||
{
|
||
m_isChannel2Outputting = true;
|
||
m_channel2OutputBtn->setEnabled(false);
|
||
m_channel2StopBtn->setEnabled(true);
|
||
m_channel2TempSpin->setEnabled(false);
|
||
|
||
// TODO: 实际发送输出命令到硬件
|
||
qDebug() << "通道2开始输出:" << m_channel2TempSpin->value() << "°C";
|
||
}
|
||
|
||
void RTDOutputWidget::onChannel2StopClicked()
|
||
{
|
||
m_isChannel2Outputting = false;
|
||
m_channel2OutputBtn->setEnabled(true);
|
||
m_channel2StopBtn->setEnabled(false);
|
||
m_channel2TempSpin->setEnabled(true);
|
||
|
||
// TODO: 发送停止输出命令到硬件
|
||
qDebug() << "通道2停止输出";
|
||
}
|
||
|
||
void RTDOutputWidget::onChannel1TempChanged(double value)
|
||
{
|
||
double resistance = convertTemperatureToResistance(value);
|
||
m_channel1ResDisplay->setText(QString::number(resistance, 'f', 2));
|
||
}
|
||
|
||
void RTDOutputWidget::onChannel2TempChanged(double value)
|
||
{
|
||
double resistance = convertTemperatureToResistance(value);
|
||
m_channel2ResDisplay->setText(QString::number(resistance, 'f', 2));
|
||
}
|
||
|
||
double RTDOutputWidget::convertTemperatureToResistance(double temperature)
|
||
{
|
||
// PT100标准公式 R(T) = R0 * (1 + A*T + B*T^2)
|
||
// R0 = 100Ω, A = 3.9083e-3, B = -5.775e-7 (0-850°C)
|
||
const double R0 = 100.0;
|
||
const double A = 3.9083e-3;
|
||
const double B = -5.775e-7;
|
||
|
||
if (temperature >= 0)
|
||
{
|
||
return R0 * (1.0 + A * temperature + B * temperature * temperature);
|
||
}
|
||
else
|
||
{
|
||
// 负温度区 R(T) = R0 * (1 + A*T + B*T^2 + C*(T-100)*T^3)
|
||
const double C = -4.183e-12;
|
||
return R0 * (1.0 + A * temperature + B * temperature * temperature +
|
||
C * (temperature - 100.0) * temperature * temperature * temperature);
|
||
}
|
||
}
|