#include "numpaddialog.h" #include #include #include #include #include #include #include "global.h" NumPadDialog::NumPadDialog(QWidget* parent) : QDialog(parent) { setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); setAttribute(Qt::WA_TranslucentBackground); setModal(true); // 覆盖整个父窗口,作为半透明遮罩 if (parent) setGeometry(parent->rect()); setStyleSheet("background-color: rgba(0,0,0,102);"); // 面板(默认居中,可用 setAnchorWidget 定位到某个控件旁边) m_panel = new QWidget(this); m_panel->setObjectName("NumPadPanel"); m_panel->setStyleSheet(QString( "QWidget#NumPadPanel{background-color:%1;border:4px solid %2;border-radius:16px;}" "QPushButton[numpad=\"true\"]{background-color:#2D3947;color:#E6EDF3;border:1px solid #3D4A59;border-radius:12px;font-size:40px;}" "QPushButton[numpad=\"true\"]:pressed{background-color:#2E7BE6;color:#FFFFFF;}" "QPushButton[numpad=\"true\"]:focus{background-color:#3D8BFD;color:#FFFFFF;border:2px solid #8ABFFF;}") .arg(C::PANEL, C::BORDER)); m_panelLay = new QVBoxLayout(m_panel); // 输入回显 m_echo = new QLineEdit(m_panel); m_echo->setReadOnly(true); m_echo->setEchoMode(QLineEdit::Password); m_echo->setAlignment(Qt::AlignCenter); m_echo->setFocusPolicy(Qt::NoFocus); // 纯显示回显:不参与 Tab 选中 m_echo->setAttribute(Qt::WA_TransparentForMouseEvents); // 且点击穿透,不响应鼠标 m_panelLay->addWidget(m_echo, 0, Qt::AlignHCenter); // 数字键区(1-9, 0, 退格, 清除/小数点) m_grid = new QGridLayout(); const QString digits[3][3] = {{"1","2","3"},{"4","5","6"},{"7","8","9"}}; for (int r = 0; r < 3; ++r) for (int c = 0; c < 3; ++c) { QPushButton* b = new QPushButton(digits[r][c], m_panel); b->setProperty("numpad", true); connect(b, &QPushButton::clicked, this, [this, d = digits[r][c]](){ onDigit(d); }); m_grid->addWidget(b, r, c); m_digits << b; } QPushButton* b0 = new QPushButton("0", m_panel); b0->setProperty("numpad", true); connect(b0, &QPushButton::clicked, this, [this](){ onDigit("0"); }); m_grid->addWidget(b0, 3, 1); m_digits << b0; m_backKey = new QPushButton("退格", m_panel); m_backKey->setProperty("numpad", true); connect(m_backKey, &QPushButton::clicked, this, &NumPadDialog::onBackspace); m_grid->addWidget(m_backKey, 3, 0); m_clearKey = new QPushButton("清除", m_panel); m_clearKey->setProperty("numpad", true); connect(m_clearKey, &QPushButton::clicked, this, [this]() { if (m_paramMode) onDot(); else onClear(); }); m_grid->addWidget(m_clearKey, 3, 2); // 确认 / 取消 m_okKey = new QPushButton("确认", m_panel); m_okKey->setProperty("numpad", true); connect(m_okKey, &QPushButton::clicked, this, &NumPadDialog::accept); m_cancelKey = new QPushButton("取消", m_panel); m_cancelKey->setProperty("numpad", true); connect(m_cancelKey, &QPushButton::clicked, this, &NumPadDialog::reject); // 确认 / 取消:单独一行、水平居中,并与数字键盘留出间隔 QHBoxLayout* okRow = new QHBoxLayout(); okRow->setSpacing(80); okRow->addStretch(1); okRow->addWidget(m_okKey); okRow->addWidget(m_cancelKey); okRow->addStretch(1); m_panelLay->addLayout(m_grid); m_panelLay->setAlignment(m_grid, Qt::AlignHCenter); m_panelLay->addLayout(okRow); m_panelLay->addStretch(1); applySizes(); // 应用尺寸(默认大字版)并摆放面板 refreshEcho(); } void NumPadDialog::setValue(const QString& v) { m_value = v.left(m_maxLen); refreshEcho(); } void NumPadDialog::clear() { m_value.clear(); refreshEcho(); } // 整体不透明度(0.0~1.0) void NumPadDialog::setOpacity(qreal opacity) { setWindowOpacity(opacity); } // 面板贴在参照控件左侧 gap 像素处弹出(垂直对齐其中心,并钳位到屏幕内) void NumPadDialog::setAnchorWidget(QWidget* ref, int gap) { m_anchor = ref; m_gap = gap; placePanel(); } // 参数输入模式:回显显示实际数字(不掩码),“清除”键换成“小数点” void NumPadDialog::setParamMode(bool on) { m_paramMode = on; m_echo->setEchoMode(on ? QLineEdit::Normal : QLineEdit::Password); m_clearKey->setText(on ? "." : "清除"); applySizes(); // 重设“小数点/清除”键的字号 } // 紧凑尺寸(按键与面板更小),默认 false = 大字版 void NumPadDialog::setCompact(bool on) { m_compact = on; applySizes(); } // 按当前尺寸模式设置面板/按键的大小与字号,并重新摆放面板 void NumPadDialog::applySizes() { const int digitFont = m_compact ? 40 : 50; const int fnFont = m_compact ? 30 : 40; const int dotFont = m_compact ? 46 : 60; const int okFont = m_compact ? 44 : 60; const QSize digitSz = m_compact ? QSize(120, 70) : QSize(150, 120); const QSize clearSz = m_compact ? QSize(120, 70) : QSize(150, 108); const QSize okSz = m_compact ? QSize(130, 88) : QSize(160, 140); m_panel->setFixedSize(m_compact ? QSize(460, 600) : QSize(600, 730)); m_panelLay->setContentsMargins(m_compact ? 20 : 24, m_compact ? 24 : 40, m_compact ? 20 : 24, m_compact ? 26 : 50); m_panelLay->setSpacing(m_compact ? 26 : 50); m_grid->setSpacing(m_compact ? 18 : 30); m_echo->setFixedSize(m_compact ? QSize(400, 70) : QSize(510, 100)); m_echo->setStyleSheet(QString("font-size:%1px;").arg(m_compact ? 48 : 70)); for (QPushButton* b : m_digits) { b->setFixedSize(digitSz); b->setStyleSheet(QString("font-size:%1px;").arg(digitFont)); } m_backKey->setFixedSize(digitSz); m_backKey->setStyleSheet(QString("font-size:%1px;").arg(fnFont)); m_clearKey->setFixedSize(clearSz); m_clearKey->setStyleSheet(QString("font-size:%1px;").arg(m_paramMode ? dotFont : fnFont)); m_okKey->setFixedSize(okSz); m_okKey->setStyleSheet(QString("font-size:%1px;").arg(okFont)); m_cancelKey->setFixedSize(okSz); m_cancelKey->setStyleSheet(cancelButtonStyle(okFont)); // 选中时红底白字 placePanel(); } // 计算面板位置:有参照控件 → 其左侧;否则居中 void NumPadDialog::placePanel() { const int w = m_panel->width(); const int h = m_panel->height(); int x = (width() - w) / 2; int y = (height() - h) / 2; if (m_anchor && m_anchor->window()) { // 面板放在参照控件左侧;对话框覆盖整个窗口,其局部坐标即窗口坐标 const QPoint p = m_anchor->mapTo(m_anchor->window(), QPoint(0, 0)); x = p.x() - m_gap - w; y = p.y() + m_anchor->height() / 2 - h / 2; } x = qBound(0, x, qMax(0, width() - w)); y = qBound(0, y, qMax(0, height() - h)); m_panel->move(x, y); } // 小数点:仅允许一个,空值时补前导 0 void NumPadDialog::onDot() { if (m_value.contains('.')) return; if (m_value.isEmpty()) m_value = "0"; if (m_value.size() >= m_maxLen) return; m_value += '.'; refreshEcho(); } void NumPadDialog::onDigit(const QString& d) { if (m_value.size() >= m_maxLen) return; // 超过最大位数忽略 m_value += d; refreshEcho(); } void NumPadDialog::onBackspace() { if (!m_value.isEmpty()) m_value.chop(1); refreshEcho(); } void NumPadDialog::onClear() { m_value.clear(); refreshEcho(); } void NumPadDialog::refreshEcho() { m_echo->setText(m_value); m_echo->setCursorPosition(m_value.size()); }