#include "signaltrimwidget.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 *TRIM_BUTTON_STYLE = R"( QPushButton { background-color: #ff9800; color: white; border: none; border-radius: 8px; padding: 12px 20px; font-size: 28px; font-weight: bold; min-width: 60px; min-height: 50px; } QPushButton:hover { background-color: #f57c00; } QPushButton:pressed { background-color: #ef6c00; } )"; SignalTrimWidget::SignalTrimWidget(QWidget *parent) : QWidget(parent), m_currentValue(0), m_minValue(-100), m_maxValue(100), m_decimals(4) { setupUI(); updateTotalValue(); } void SignalTrimWidget::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); // 信号选择面板 contentLayout->addWidget(createSignalSelectPanel()); // 粗调面板 contentLayout->addWidget(createCoarseAdjustPanel()); // 微调面板 contentLayout->addWidget(createFineAdjustPanel()); // 输出面板 contentLayout->addWidget(createOutputPanel()); contentLayout->addStretch(); scrollArea->setWidget(contentWidget); mainLayout->addWidget(scrollArea, 1); } QWidget *SignalTrimWidget::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, &SignalTrimWidget::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 *SignalTrimWidget::createSignalSelectPanel() { QGroupBox *group = new QGroupBox("信号选择"); group->setStyleSheet(GROUP_STYLE); QHBoxLayout *layout = new QHBoxLayout(group); layout->setContentsMargins(16, 24, 16, 16); layout->setSpacing(24); // 信号类型 QVBoxLayout *typeLayout = new QVBoxLayout; QLabel *typeLabel = new QLabel("信号类型"); typeLabel->setStyleSheet("color: #666; font-size: 12px; font-weight: normal;"); m_signalTypeCombo = new QComboBox; m_signalTypeCombo->addItems({"直流电压 (DC V)", "直流电流 (DC mA)", "交流电压 (AC V)", "电阻 (Ω)", "热电偶 (°C)", "热电阻 (°C)", "频率 (Hz)"}); m_signalTypeCombo->setStyleSheet(R"( QComboBox { background: white; border: 1px solid #ddd; border-radius: 6px; padding: 10px 16px; min-width: 180px; font-size: 14px; } )"); connect(m_signalTypeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &SignalTrimWidget::onSignalTypeChanged); typeLayout->addWidget(typeLabel); typeLayout->addWidget(m_signalTypeCombo); layout->addLayout(typeLayout); // 单位选择 QVBoxLayout *unitLayout = new QVBoxLayout; QLabel *unitLabel = new QLabel("单位"); unitLabel->setStyleSheet("color: #666; font-size: 12px; font-weight: normal;"); m_unitCombo = new QComboBox; m_unitCombo->addItems({"V", "mV", "µV"}); m_unitCombo->setStyleSheet(R"( QComboBox { background: white; border: 1px solid #ddd; border-radius: 6px; padding: 10px 16px; min-width: 100px; font-size: 14px; } )"); unitLayout->addWidget(unitLabel); unitLayout->addWidget(m_unitCombo); layout->addLayout(unitLayout); layout->addStretch(); return group; } QWidget *SignalTrimWidget::createCoarseAdjustPanel() { QGroupBox *group = new QGroupBox("粗调"); group->setStyleSheet(GROUP_STYLE); QHBoxLayout *layout = new QHBoxLayout(group); layout->setContentsMargins(16, 24, 16, 16); layout->setSpacing(16); QLabel *valueLabel = new QLabel("设定值:"); valueLabel->setStyleSheet("font-size: 16px; font-weight: 600;"); layout->addWidget(valueLabel); m_coarseValueSpin = new QDoubleSpinBox; m_coarseValueSpin->setRange(m_minValue, m_maxValue); m_coarseValueSpin->setValue(0); m_coarseValueSpin->setDecimals(m_decimals); m_coarseValueSpin->setSingleStep(1.0); m_coarseValueSpin->setStyleSheet(R"( QDoubleSpinBox { padding: 12px 16px; border: 2px solid #2196F3; border-radius: 8px; background: white; font-size: 24px; font-weight: bold; font-family: monospace; min-width: 200px; } QDoubleSpinBox::up-button, QDoubleSpinBox::down-button { subcontrol-origin: border; width: 32px; border-left: 2px solid #2196F3; background: #e3f2fd; } QDoubleSpinBox::up-button { subcontrol-position: top right; border-top-right-radius: 6px; } QDoubleSpinBox::down-button { subcontrol-position: bottom right; border-bottom-right-radius: 6px; } QDoubleSpinBox::up-button:hover, QDoubleSpinBox::down-button:hover { background: #bbdefb; } QDoubleSpinBox::up-arrow { image: url(:/icons/arrow_up.svg); width: 14px; height: 14px; } QDoubleSpinBox::down-arrow { image: url(:/icons/arrow_down.svg); width: 14px; height: 14px; } )"); connect(m_coarseValueSpin, QOverload::of(&QDoubleSpinBox::valueChanged), this, &SignalTrimWidget::onCoarseValueChanged); layout->addWidget(m_coarseValueSpin); m_coarseUnitLabel = new QLabel("V"); m_coarseUnitLabel->setStyleSheet("font-size: 20px; font-weight: bold; color: #2196F3;"); layout->addWidget(m_coarseUnitLabel); layout->addStretch(); // 快捷设置按钮 QVBoxLayout *presetLayout = new QVBoxLayout; QLabel *presetLabel = new QLabel("快捷设置:"); presetLabel->setStyleSheet("color: #666; font-size: 12px;"); presetLayout->addWidget(presetLabel); QHBoxLayout *presetBtnLayout = new QHBoxLayout; QStringList presets = {"0", "1", "5", "10", "20"}; for (const QString &preset : presets) { QPushButton *btn = new QPushButton(preset); btn->setStyleSheet(R"( QPushButton { background-color: #e3f2fd; color: #1976D2; border: 1px solid #90caf9; border-radius: 6px; padding: 8px 16px; font-weight: 600; } QPushButton:hover { background-color: #bbdefb; } )"); btn->setCursor(Qt::PointingHandCursor); connect(btn, &QPushButton::clicked, this, [this, preset]() { m_coarseValueSpin->setValue(preset.toDouble()); }); presetBtnLayout->addWidget(btn); } presetLayout->addLayout(presetBtnLayout); layout->addLayout(presetLayout); return group; } QWidget *SignalTrimWidget::createFineAdjustPanel() { QGroupBox *group = new QGroupBox("微调"); group->setStyleSheet(GROUP_STYLE); QVBoxLayout *mainLayout = new QVBoxLayout(group); mainLayout->setContentsMargins(16, 24, 16, 16); mainLayout->setSpacing(16); // 步进选择 QHBoxLayout *stepLayout = new QHBoxLayout; QLabel *stepLabel = new QLabel("微调步进:"); stepLabel->setStyleSheet("font-weight: 600;"); stepLayout->addWidget(stepLabel); m_stepSizeCombo = new QComboBox; m_stepSizeCombo->addItems({"0.0001", "0.001", "0.01", "0.1", "1"}); m_stepSizeCombo->setCurrentIndex(1); // 默认 0.001 m_stepSizeCombo->setStyleSheet(R"( QComboBox { background: white; border: 1px solid #ddd; border-radius: 6px; padding: 8px 12px; min-width: 100px; } )"); connect(m_stepSizeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, [this](int) { updateSliderRange(); }); stepLayout->addWidget(m_stepSizeCombo); stepLayout->addStretch(); mainLayout->addLayout(stepLayout); // 微调控制 QHBoxLayout *trimLayout = new QHBoxLayout; trimLayout->setSpacing(16); // 减少按钮 m_decrementBtn = new QPushButton("-"); m_decrementBtn->setStyleSheet(TRIM_BUTTON_STYLE); m_decrementBtn->setCursor(Qt::PointingHandCursor); connect(m_decrementBtn, &QPushButton::clicked, this, &SignalTrimWidget::onDecrementClicked); trimLayout->addWidget(m_decrementBtn); // 微调值显示 m_fineValueSpin = new QDoubleSpinBox; m_fineValueSpin->setRange(-10, 10); m_fineValueSpin->setValue(0); m_fineValueSpin->setDecimals(4); m_fineValueSpin->setSingleStep(0.001); m_fineValueSpin->setPrefix("微调: "); m_fineValueSpin->setStyleSheet(R"( QDoubleSpinBox { padding: 12px 16px; border: 2px solid #ff9800; border-radius: 8px; background: #fff3e0; font-size: 18px; font-weight: bold; font-family: monospace; min-width: 180px; } QDoubleSpinBox::up-button, QDoubleSpinBox::down-button { subcontrol-origin: border; width: 28px; border-left: 2px solid #ff9800; background: #ffe0b2; } QDoubleSpinBox::up-button { subcontrol-position: top right; border-top-right-radius: 6px; } QDoubleSpinBox::down-button { subcontrol-position: bottom right; border-bottom-right-radius: 6px; } QDoubleSpinBox::up-button:hover, QDoubleSpinBox::down-button:hover { background: #ffcc80; } 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_fineValueSpin, QOverload::of(&QDoubleSpinBox::valueChanged), this, &SignalTrimWidget::onFineValueChanged); trimLayout->addWidget(m_fineValueSpin); // 增加按钮 m_incrementBtn = new QPushButton("+"); m_incrementBtn->setStyleSheet(TRIM_BUTTON_STYLE); m_incrementBtn->setCursor(Qt::PointingHandCursor); connect(m_incrementBtn, &QPushButton::clicked, this, &SignalTrimWidget::onIncrementClicked); trimLayout->addWidget(m_incrementBtn); trimLayout->addStretch(); mainLayout->addLayout(trimLayout); // 滑块微调 QHBoxLayout *sliderLayout = new QHBoxLayout; QLabel *minLabel = new QLabel("-1.000"); minLabel->setStyleSheet("color: #666; font-family: monospace;"); sliderLayout->addWidget(minLabel); m_fineSlider = new QSlider(Qt::Horizontal); m_fineSlider->setRange(-1000, 1000); m_fineSlider->setValue(0); m_fineSlider->setStyleSheet(R"( QSlider::groove:horizontal { border: 1px solid #bbb; background: #e0e0e0; height: 8px; border-radius: 4px; } QSlider::handle:horizontal { background: #ff9800; border: 2px solid #f57c00; width: 24px; margin: -8px 0; border-radius: 12px; } QSlider::handle:horizontal:hover { background: #ffa726; } QSlider::sub-page:horizontal { background: #ffcc80; border-radius: 4px; } )"); connect(m_fineSlider, &QSlider::valueChanged, this, &SignalTrimWidget::onSliderChanged); sliderLayout->addWidget(m_fineSlider, 1); QLabel *maxLabel = new QLabel("+1.000"); maxLabel->setStyleSheet("color: #666; font-family: monospace;"); sliderLayout->addWidget(maxLabel); mainLayout->addLayout(sliderLayout); return group; } QWidget *SignalTrimWidget::createOutputPanel() { QGroupBox *group = new QGroupBox("最终输出"); group->setStyleSheet(GROUP_STYLE); QHBoxLayout *layout = new QHBoxLayout(group); layout->setContentsMargins(16, 24, 16, 16); layout->setSpacing(24); // 总值显示 m_totalValueLabel = new QLabel("0.0000 V"); m_totalValueLabel->setStyleSheet(R"( QLabel { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #1a1a2e, stop:1 #16213e); color: #00ff88; border: 2px solid #00aa55; border-radius: 12px; padding: 20px 40px; font-size: 36px; font-weight: bold; font-family: 'Courier New', monospace; min-width: 300px; } )"); m_totalValueLabel->setAlignment(Qt::AlignCenter); layout->addWidget(m_totalValueLabel); layout->addStretch(); // 控制按钮 QVBoxLayout *btnLayout = new QVBoxLayout; btnLayout->setSpacing(12); m_applyBtn = new QPushButton("应用输出"); m_applyBtn->setStyleSheet(BUTTON_STYLE); m_applyBtn->setCursor(Qt::PointingHandCursor); connect(m_applyBtn, &QPushButton::clicked, this, &SignalTrimWidget::onApplyOutput); btnLayout->addWidget(m_applyBtn); m_resetBtn = new QPushButton("重置归零"); m_resetBtn->setStyleSheet(R"( QPushButton { background-color: #757575; color: white; border: none; border-radius: 8px; padding: 12px 32px; font-size: 14px; font-weight: 600; } QPushButton:hover { background-color: #616161; } )"); m_resetBtn->setCursor(Qt::PointingHandCursor); connect(m_resetBtn, &QPushButton::clicked, this, &SignalTrimWidget::onResetValue); btnLayout->addWidget(m_resetBtn); layout->addLayout(btnLayout); return group; } void SignalTrimWidget::onSignalTypeChanged(int index) { // 根据信号类型更新单位选项 m_unitCombo->clear(); switch (index) { case 0: // DC V m_unitCombo->addItems({"V", "mV", "µV"}); m_coarseUnitLabel->setText("V"); m_minValue = -100; m_maxValue = 100; m_decimals = 4; break; case 1: // DC mA m_unitCombo->addItems({"mA", "µA"}); m_coarseUnitLabel->setText("mA"); m_minValue = -30; m_maxValue = 30; m_decimals = 4; break; case 2: // AC V m_unitCombo->addItems({"V", "mV"}); m_coarseUnitLabel->setText("V"); m_minValue = 0; m_maxValue = 300; m_decimals = 3; break; case 3: // Ω m_unitCombo->addItems({"Ω", "kΩ", "MΩ"}); m_coarseUnitLabel->setText("Ω"); m_minValue = 0; m_maxValue = 10000; m_decimals = 2; break; case 4: // 热电偶 case 5: // 热电阻 m_unitCombo->addItems({"°C"}); m_coarseUnitLabel->setText("°C"); m_minValue = -200; m_maxValue = 1800; m_decimals = 2; break; case 6: // Hz m_unitCombo->addItems({"Hz", "kHz", "MHz"}); m_coarseUnitLabel->setText("Hz"); m_minValue = 0; m_maxValue = 100000; m_decimals = 2; break; } m_coarseValueSpin->setRange(m_minValue, m_maxValue); m_coarseValueSpin->setDecimals(m_decimals); updateTotalValue(); } void SignalTrimWidget::onCoarseValueChanged(double value) { Q_UNUSED(value) updateTotalValue(); } void SignalTrimWidget::onFineValueChanged(double value) { // 更新滑块位置 m_fineSlider->blockSignals(true); double step = m_stepSizeCombo->currentText().toDouble(); m_fineSlider->setValue(static_cast(value / step)); m_fineSlider->blockSignals(false); updateTotalValue(); } void SignalTrimWidget::onSliderChanged(int value) { double step = m_stepSizeCombo->currentText().toDouble(); m_fineValueSpin->setValue(value * step); } void SignalTrimWidget::onIncrementClicked() { double step = m_stepSizeCombo->currentText().toDouble(); m_fineValueSpin->setValue(m_fineValueSpin->value() + step); } void SignalTrimWidget::onDecrementClicked() { double step = m_stepSizeCombo->currentText().toDouble(); m_fineValueSpin->setValue(m_fineValueSpin->value() - step); } void SignalTrimWidget::onApplyOutput() { // 应用输出值到设备 m_currentValue = m_coarseValueSpin->value() + m_fineValueSpin->value(); // TODO: 发送到硬件 } void SignalTrimWidget::onResetValue() { m_coarseValueSpin->setValue(0); m_fineValueSpin->setValue(0); m_fineSlider->setValue(0); } void SignalTrimWidget::updateTotalValue() { double total = m_coarseValueSpin->value() + m_fineValueSpin->value(); QString unit = m_coarseUnitLabel->text(); m_totalValueLabel->setText(QString("%1 %2").arg(total, 0, 'f', m_decimals).arg(unit)); } void SignalTrimWidget::updateSliderRange() { double step = m_stepSizeCombo->currentText().toDouble(); int range = static_cast(1.0 / step); m_fineSlider->setRange(-range, range); m_fineValueSpin->setSingleStep(step); }