Files
QT_wuhan_YT/widgets/numpaddialog.cpp
T
2026-10-14 09:59:42 +08:00

238 lines
7.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "numpaddialog.h"
#include <QVBoxLayout>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QLabel>
#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());
}