#include "dualchannelwidget.h" #include #include #include #include #include #include static const char *GROUP_STYLE = R"( QGroupBox { background-color: white; border: 1px solid #e0e0e0; border-radius: 12px; margin-top: 8px; padding: 16px; font-size: 14px; font-weight: 600; } QGroupBox::title { subcontrol-origin: margin; left: 16px; padding: 0 8px; color: #333; } )"; static const char *BUTTON_STYLE = R"( QPushButton { background-color: #2196F3; color: white; border: none; border-radius: 8px; padding: 12px 32px; font-size: 14px; font-weight: 600; } QPushButton:hover { background-color: #1976D2; } QPushButton:pressed { background-color: #1565C0; } QPushButton:disabled { background-color: #BDBDBD; } )"; static const char *STOP_BUTTON_STYLE = R"( QPushButton { background-color: #f44336; color: white; border: none; border-radius: 8px; padding: 12px 32px; font-size: 14px; font-weight: 600; } QPushButton:hover { background-color: #d32f2f; } QPushButton:pressed { background-color: #c62828; } QPushButton:disabled { background-color: #BDBDBD; } )"; static const char *VALUE_DISPLAY_STYLE = R"( QLabel { background-color: #1a1a2e; color: #00ff88; border: 1px solid #333; border-radius: 8px; padding: 16px; font-size: 28px; font-weight: bold; font-family: 'Courier New', monospace; min-width: 200px; } )"; DualChannelWidget::DualChannelWidget(QWidget *parent) : QWidget(parent), m_isOutputting(false) { setupUI(); m_measureTimer = new QTimer(this); connect(m_measureTimer, &QTimer::timeout, this, &DualChannelWidget::updateMeasurement); } void DualChannelWidget::setupUI() { QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); // 标题栏 mainLayout->addWidget(createTitleBar()); // 内容区域 QScrollArea *scrollArea = new QScrollArea; scrollArea->setWidgetResizable(true); scrollArea->setFrameShape(QFrame::NoFrame); scrollArea->setStyleSheet("QScrollArea { background-color: #f5f5f5; }"); QWidget *contentWidget = new QWidget; contentWidget->setStyleSheet("background-color: #f5f5f5;"); QVBoxLayout *contentLayout = new QVBoxLayout(contentWidget); contentLayout->setContentsMargins(20, 20, 20, 20); contentLayout->setSpacing(16); // 双通道输出面板 QHBoxLayout *channelsLayout = new QHBoxLayout; channelsLayout->setSpacing(16); channelsLayout->addWidget(createChannel1Panel()); channelsLayout->addWidget(createChannel2Panel()); contentLayout->addLayout(channelsLayout); // 测量显示面板 contentLayout->addWidget(createMeasurementPanel()); // 控制面板 contentLayout->addWidget(createControlPanel()); contentLayout->addStretch(); scrollArea->setWidget(contentWidget); mainLayout->addWidget(scrollArea, 1); } QWidget *DualChannelWidget::createTitleBar() { QWidget *titleBar = new QWidget; titleBar->setFixedHeight(60); titleBar->setStyleSheet("background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #1976D2, stop:1 #1565C0);"); QHBoxLayout *layout = new QHBoxLayout(titleBar); layout->setContentsMargins(16, 0, 16, 0); // 返回按钮 m_backBtn = new QPushButton("← 返回"); m_backBtn->setCursor(Qt::PointingHandCursor); m_backBtn->setStyleSheet(R"( QPushButton { background: rgba(255,255,255,0.2); color: white; border: none; border-radius: 6px; padding: 8px 16px; font-size: 14px; } QPushButton:hover { background: rgba(255,255,255,0.3); } )"); connect(m_backBtn, &QPushButton::clicked, this, &DualChannelWidget::backRequested); layout->addWidget(m_backBtn); // 标题(居中) m_titleLabel = new QLabel("双通道"); m_titleLabel->setStyleSheet("color: white; font-size: 18px; font-weight: bold;"); m_titleLabel->setAlignment(Qt::AlignCenter); layout->addWidget(m_titleLabel, 1); // 右侧占位,保持标题居中 QWidget *spacer = new QWidget; spacer->setFixedWidth(m_backBtn->sizeHint().width()); layout->addWidget(spacer); return titleBar; } QWidget *DualChannelWidget::createChannel1Panel() { QGroupBox *group = new QGroupBox("通道1 - 输出"); group->setStyleSheet(GROUP_STYLE); QVBoxLayout *layout = new QVBoxLayout(group); layout->setContentsMargins(16, 24, 16, 16); layout->setSpacing(16); // 启用复选框 m_ch1EnableCheck = new QCheckBox("启用通道1"); m_ch1EnableCheck->setChecked(true); m_ch1EnableCheck->setStyleSheet("font-weight: 600; color: #00aa55;"); layout->addWidget(m_ch1EnableCheck); // 信号类型选择 QHBoxLayout *typeLayout = new QHBoxLayout; typeLayout->addWidget(new QLabel("信号类型:")); m_ch1TypeCombo = new QComboBox; m_ch1TypeCombo->addItems({"直流电压 (V)", "直流电流 (mA)", "电阻 (Ω)", "频率 (Hz)"}); m_ch1TypeCombo->setStyleSheet(R"( QComboBox { background: white; border: 1px solid #ddd; border-radius: 6px; padding: 8px 12px; min-width: 150px; } )"); connect(m_ch1TypeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int) { onChannel1OutputChanged(); }); typeLayout->addWidget(m_ch1TypeCombo); typeLayout->addStretch(); layout->addLayout(typeLayout); // 输出值设置 QHBoxLayout *valueLayout = new QHBoxLayout; valueLayout->addWidget(new QLabel("输出值:")); m_ch1ValueSpin = new QDoubleSpinBox; m_ch1ValueSpin->setRange(-100, 100); m_ch1ValueSpin->setValue(5.0); m_ch1ValueSpin->setDecimals(4); m_ch1ValueSpin->setSuffix(" V"); m_ch1ValueSpin->setStyleSheet(R"( QDoubleSpinBox { padding: 8px 12px; border: 1px solid #ddd; border-radius: 6px; background: white; font-size: 16px; font-weight: bold; min-width: 150px; } QDoubleSpinBox::up-button, QDoubleSpinBox::down-button { subcontrol-origin: border; width: 24px; border-left: 1px solid #ddd; background: #f5f5f5; } QDoubleSpinBox::up-button { subcontrol-position: top right; border-top-right-radius: 5px; } QDoubleSpinBox::down-button { subcontrol-position: bottom right; border-bottom-right-radius: 5px; } QDoubleSpinBox::up-button:hover, QDoubleSpinBox::down-button:hover { background: #e0e0e0; } QDoubleSpinBox::up-arrow { image: url(:/icons/arrow_up.svg); width: 12px; height: 12px; } QDoubleSpinBox::down-arrow { image: url(:/icons/arrow_down.svg); width: 12px; height: 12px; } )"); connect(m_ch1ValueSpin, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this](double) { onChannel1OutputChanged(); }); valueLayout->addWidget(m_ch1ValueSpin); valueLayout->addStretch(); layout->addLayout(valueLayout); // 实际测量值显示 QLabel *measureTitle = new QLabel("实际测量:"); measureTitle->setStyleSheet("color: #666;"); layout->addWidget(measureTitle); m_ch1MeasureLabel = new QLabel("-- V"); m_ch1MeasureLabel->setStyleSheet(VALUE_DISPLAY_STYLE); m_ch1MeasureLabel->setAlignment(Qt::AlignCenter); layout->addWidget(m_ch1MeasureLabel); layout->addStretch(); return group; } QWidget *DualChannelWidget::createChannel2Panel() { QGroupBox *group = new QGroupBox("通道2 - 输出"); group->setStyleSheet(GROUP_STYLE); QVBoxLayout *layout = new QVBoxLayout(group); layout->setContentsMargins(16, 24, 16, 16); layout->setSpacing(16); // 启用复选框 m_ch2EnableCheck = new QCheckBox("启用通道2"); m_ch2EnableCheck->setChecked(true); m_ch2EnableCheck->setStyleSheet("font-weight: 600; color: #d32f2f;"); layout->addWidget(m_ch2EnableCheck); // 信号类型选择 QHBoxLayout *typeLayout = new QHBoxLayout; typeLayout->addWidget(new QLabel("信号类型:")); m_ch2TypeCombo = new QComboBox; m_ch2TypeCombo->addItems({"直流电压 (V)", "直流电流 (mA)", "电阻 (Ω)", "频率 (Hz)"}); m_ch2TypeCombo->setStyleSheet(R"( QComboBox { background: white; border: 1px solid #ddd; border-radius: 6px; padding: 8px 12px; min-width: 150px; } )"); connect(m_ch2TypeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int) { onChannel2OutputChanged(); }); typeLayout->addWidget(m_ch2TypeCombo); typeLayout->addStretch(); layout->addLayout(typeLayout); // 输出值设置 QHBoxLayout *valueLayout = new QHBoxLayout; valueLayout->addWidget(new QLabel("输出值:")); m_ch2ValueSpin = new QDoubleSpinBox; m_ch2ValueSpin->setRange(-100, 100); m_ch2ValueSpin->setValue(10.0); m_ch2ValueSpin->setDecimals(4); m_ch2ValueSpin->setSuffix(" V"); m_ch2ValueSpin->setStyleSheet(R"( QDoubleSpinBox { padding: 8px 12px; border: 1px solid #ddd; border-radius: 6px; background: white; font-size: 16px; font-weight: bold; min-width: 150px; } QDoubleSpinBox::up-button, QDoubleSpinBox::down-button { subcontrol-origin: border; width: 24px; border-left: 1px solid #ddd; background: #f5f5f5; } QDoubleSpinBox::up-button { subcontrol-position: top right; border-top-right-radius: 5px; } QDoubleSpinBox::down-button { subcontrol-position: bottom right; border-bottom-right-radius: 5px; } QDoubleSpinBox::up-button:hover, QDoubleSpinBox::down-button:hover { background: #e0e0e0; } QDoubleSpinBox::up-arrow { image: url(:/icons/arrow_up.svg); width: 12px; height: 12px; } QDoubleSpinBox::down-arrow { image: url(:/icons/arrow_down.svg); width: 12px; height: 12px; } )"); connect(m_ch2ValueSpin, QOverload::of(&QDoubleSpinBox::valueChanged), this, [this](double) { onChannel2OutputChanged(); }); valueLayout->addWidget(m_ch2ValueSpin); valueLayout->addStretch(); layout->addLayout(valueLayout); // 实际测量值显示 QLabel *measureTitle = new QLabel("实际测量:"); measureTitle->setStyleSheet("color: #666;"); layout->addWidget(measureTitle); m_ch2MeasureLabel = new QLabel("-- V"); m_ch2MeasureLabel->setStyleSheet(R"( QLabel { background-color: #1a1a2e; color: #ff6b6b; border: 1px solid #333; border-radius: 8px; padding: 16px; font-size: 28px; font-weight: bold; font-family: 'Courier New', monospace; min-width: 200px; } )"); m_ch2MeasureLabel->setAlignment(Qt::AlignCenter); layout->addWidget(m_ch2MeasureLabel); layout->addStretch(); return group; } QWidget *DualChannelWidget::createMeasurementPanel() { QGroupBox *group = new QGroupBox("采集输入"); group->setStyleSheet(GROUP_STYLE); QHBoxLayout *layout = new QHBoxLayout(group); layout->setContentsMargins(16, 24, 16, 16); layout->setSpacing(32); // 通道1输入 QVBoxLayout *ch1Layout = new QVBoxLayout; QLabel *ch1Title = new QLabel("通道1 采集"); ch1Title->setStyleSheet("font-weight: 600; color: #00aa55;"); ch1Layout->addWidget(ch1Title); m_ch1InputLabel = new QLabel("-- V"); m_ch1InputLabel->setStyleSheet(R"( QLabel { background-color: #e8f5e9; color: #2e7d32; border: 2px solid #4caf50; border-radius: 8px; padding: 12px 24px; font-size: 24px; font-weight: bold; font-family: monospace; } )"); m_ch1InputLabel->setAlignment(Qt::AlignCenter); ch1Layout->addWidget(m_ch1InputLabel); layout->addLayout(ch1Layout); // 通道2输入 QVBoxLayout *ch2Layout = new QVBoxLayout; QLabel *ch2Title = new QLabel("通道2 采集"); ch2Title->setStyleSheet("font-weight: 600; color: #d32f2f;"); ch2Layout->addWidget(ch2Title); m_ch2InputLabel = new QLabel("-- V"); m_ch2InputLabel->setStyleSheet(R"( QLabel { background-color: #ffebee; color: #c62828; border: 2px solid #f44336; border-radius: 8px; padding: 12px 24px; font-size: 24px; font-weight: bold; font-family: monospace; } )"); m_ch2InputLabel->setAlignment(Qt::AlignCenter); ch2Layout->addWidget(m_ch2InputLabel); layout->addLayout(ch2Layout); layout->addStretch(); return group; } QWidget *DualChannelWidget::createControlPanel() { QGroupBox *group = new QGroupBox("控制"); group->setStyleSheet(GROUP_STYLE); QHBoxLayout *layout = new QHBoxLayout(group); layout->setContentsMargins(16, 24, 16, 16); layout->setSpacing(16); // 同步控制 m_syncCheck = new QCheckBox("同步输出(两通道同步变化)"); m_syncCheck->setStyleSheet("font-weight: 600;"); connect(m_syncCheck, &QCheckBox::toggled, this, &DualChannelWidget::onSyncToggled); layout->addWidget(m_syncCheck); layout->addStretch(); // 开始按钮 m_startBtn = new QPushButton("开始输出"); m_startBtn->setStyleSheet(BUTTON_STYLE); m_startBtn->setCursor(Qt::PointingHandCursor); connect(m_startBtn, &QPushButton::clicked, this, &DualChannelWidget::onStartOutput); layout->addWidget(m_startBtn); // 停止按钮 m_stopBtn = new QPushButton("停止输出"); m_stopBtn->setStyleSheet(STOP_BUTTON_STYLE); m_stopBtn->setCursor(Qt::PointingHandCursor); m_stopBtn->setEnabled(false); connect(m_stopBtn, &QPushButton::clicked, this, &DualChannelWidget::onStopOutput); layout->addWidget(m_stopBtn); return group; } void DualChannelWidget::onChannel1OutputChanged() { QStringList suffixes = {" V", " mA", " Ω", " Hz"}; m_ch1ValueSpin->setSuffix(suffixes[m_ch1TypeCombo->currentIndex()]); } void DualChannelWidget::onChannel2OutputChanged() { QStringList suffixes = {" V", " mA", " Ω", " Hz"}; m_ch2ValueSpin->setSuffix(suffixes[m_ch2TypeCombo->currentIndex()]); } void DualChannelWidget::onSyncToggled(bool checked) { if (checked) { // 同步通道2到通道1的设置 m_ch2TypeCombo->setCurrentIndex(m_ch1TypeCombo->currentIndex()); m_ch2ValueSpin->setValue(m_ch1ValueSpin->value()); } } void DualChannelWidget::onStartOutput() { m_isOutputting = true; m_startBtn->setEnabled(false); m_stopBtn->setEnabled(true); m_measureTimer->start(100); } void DualChannelWidget::onStopOutput() { m_isOutputting = false; m_measureTimer->stop(); m_startBtn->setEnabled(true); m_stopBtn->setEnabled(false); m_ch1MeasureLabel->setText("-- V"); m_ch2MeasureLabel->setText("-- V"); m_ch1InputLabel->setText("-- V"); m_ch2InputLabel->setText("-- V"); } void DualChannelWidget::updateMeasurement() { static std::random_device rd; static std::mt19937 gen(rd()); static std::normal_distribution<> noise(0, 0.001); QStringList units = {"V", "mA", "Ω", "Hz"}; if (m_ch1EnableCheck->isChecked()) { double value = m_ch1ValueSpin->value() + noise(gen); m_ch1MeasureLabel->setText(QString("%1 %2") .arg(value, 0, 'f', 4) .arg(units[m_ch1TypeCombo->currentIndex()])); // 模拟采集输入 double inputValue = value * 0.98 + noise(gen) * 10; m_ch1InputLabel->setText(QString("%1 %2") .arg(inputValue, 0, 'f', 4) .arg(units[m_ch1TypeCombo->currentIndex()])); } if (m_ch2EnableCheck->isChecked()) { double value = m_ch2ValueSpin->value() + noise(gen); m_ch2MeasureLabel->setText(QString("%1 %2") .arg(value, 0, 'f', 4) .arg(units[m_ch2TypeCombo->currentIndex()])); // 模拟采集输入 double inputValue = value * 0.98 + noise(gen) * 10; m_ch2InputLabel->setText(QString("%1 %2") .arg(inputValue, 0, 'f', 4) .arg(units[m_ch2TypeCombo->currentIndex()])); } }