#include "paramcontrol.h" #include "numpaddialog.h" #include "global.h" #include #include #include #include #include #include #include "global.h" ParamControl::ParamControl(const QString& name, const QString& unit, double step, double min, double max, bool withSave, bool withFactory, QWidget* parent) : QWidget(parent), m_name(name), m_unit(unit), m_step(step), m_min(min), m_max(max), m_value(min) { QVBoxLayout* lay = new QVBoxLayout(this); lay->setContentsMargins(12, 8, 12, 8); lay->setSpacing(6); // 参数名 m_nameLabel = new QLabel(name, this); m_nameLabel->setProperty("sub", true); m_nameLabel->setStyleSheet(QString("color:%1;font-size:40px;").arg(C::TEXT_SUB)); lay->addWidget(m_nameLabel); // 数值输入框 + 单位(同一行;框内只显示数值) m_valRow = new QHBoxLayout(); m_valRow->setSpacing(12); m_valueEdit = new QLineEdit(this); m_valueEdit->setReadOnly(true); m_valueEdit->setAlignment(Qt::AlignCenter); m_valueEdit->setFocusPolicy(Qt::StrongFocus); m_valueEdit->setFixedWidth(150); // 输入框长度(按需调整) m_valueEdit->setStyleSheet("font-size:40px;font-weight:700;"); m_valueEdit->installEventFilter(this); m_valRow->addStretch(0); // 行首弹性空间:setCentered(true) 时置 1,数值行即居中 m_valRow->addWidget(m_valueEdit); m_unitLabel = new QLabel(unit, this); m_unitLabel->setStyleSheet(QString("color:%1;font-size:40px;").arg(C::TEXT_SUB)); // 同一行右侧还有按钮时,给单位固定占位,保证各参数的按钮 x 一致 // (110 取全项目最长单位“L/min”在 40px 字号下的宽度约 101px) if (withSave || withFactory) m_unitLabel->setFixedWidth(110); m_valRow->addWidget(m_unitLabel); // 保存 / 恢复出厂值(可选):跟在单位后面,与输入框同一行、整体左对齐 if (withSave) { m_save = new QPushButton("保存", this); m_save->setProperty("variant", "primary"); m_save->setFixedSize(140, 60); // 固定宽高,不再随布局拉伸 connect(m_save, &QPushButton::clicked, this, &ParamControl::saveClicked); m_valRow->addWidget(m_save); } if (withFactory) { m_factory = new QPushButton("恢复出厂值", this); m_factory->setMinimumHeight(56); connect(m_factory, &QPushButton::clicked, this, &ParamControl::factoryResetClicked); m_valRow->addWidget(m_factory); } m_valRow->addStretch(1); lay->addLayout(m_valRow); refresh(); } void ParamControl::setValue(double v) { m_value = qBound(m_min, v, m_max); refresh(); } QWidget* ParamControl::editor() const { return m_valueEdit; } void ParamControl::setEnabled(bool enabled) { QWidget::setEnabled(enabled); } void ParamControl::setCentered(bool on) { m_nameLabel->setAlignment(on ? Qt::AlignCenter : (Qt::AlignLeft | Qt::AlignVCenter)); m_valRow->setStretch(0, on ? 1 : 0); // 行首弹性空间与行尾均分 → 整行居中(含保存按钮) } // 旋钮接口:steps > 0 调大、< 0 调小(每格 = m_step,自动钳位到 [min, max]) // 目前由数值框上的 ↑/↓ 键驱动,后续接面板机械旋钮也走这里 void ParamControl::adjustByKnob(int steps) { if (steps == 0) return; const double old = m_value; setValue(old + steps * m_step); if (m_value != old) emit valueChanged(m_value); } // 点击数值框 / 空格 → 弹出数字键盘(面板靠左、不透明度 80%);↑/↓ → 每档加减一次 bool ParamControl::eventFilter(QObject* obj, QEvent* ev) { if (obj == m_valueEdit) { if (ev->type() == QEvent::MouseButtonPress) { openNumPad(); return true; } if (ev->type() == QEvent::KeyPress) { QKeyEvent* ke = static_cast(ev); const int k = ke->key(); if (Keys::space(k)) { openNumPad(); return true; } // 旋钮档:↑ 加一档、↓ 减一档(每档 = m_step)。Tab/Shift+Tab 走焦点链, // 各不重叠;按住方向键由按键自动重复继续调 if (Keys::up(k)) { adjustByKnob(1); return true; } if (Keys::down(k)) { adjustByKnob(-1); return true; } } } return QWidget::eventFilter(obj, ev); } void ParamControl::openNumPad() { NumPadDialog dlg(window()); // 以顶层窗口为父:遮罩覆盖整屏 dlg.setParamMode(true); // 参数模式:回显显示实际数字,“清除”换成“小数点” dlg.setCompact(true); // 紧凑尺寸(不影响密码页的大键盘) dlg.setAnchorWidget(m_valueEdit, 20); // 面板贴在输入框左侧 20px 处弹出 dlg.setMaxLen(6); dlg.setValue(m_step < 1.0 ? QString::number(m_value, 'f', 1) : QString::number(m_value, 'f', 0)); if (dlg.exec() != QDialog::Accepted) return; bool ok = false; const double v = dlg.value().toDouble(&ok); if (!ok) return; const double old = m_value; setValue(v); if (m_value != old) emit valueChanged(m_value); } void ParamControl::refresh() { // 框内只显示数值(单位在框后面的标签里) if (m_step < 1.0) m_valueEdit->setText(QString::number(m_value, 'f', 1)); else m_valueEdit->setText(QString::number(m_value, 'f', 0)); }