#include "signalmeasurementwidget.h" #include "overlaydialogswidget.h" #include #include #include #include #include #include #include // ============== 样式常量定义 ============== 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(widget)) { if (spin->property("minusButton").isValid()) { auto *minusBtn = qvariant_cast(spin->property("minusButton")); auto *plusBtn = qvariant_cast(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::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> channels = { {ChannelManager::INPUT_CHANNEL_1, "输入通道1"}, {ChannelManager::INPUT_CHANNEL_2, "输入通道2"}}; auto *channelLayout = qobject_cast(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(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::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::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::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); } }