Files
NumKeyBoard/numkeydia.cpp
T
2026-05-21 15:18:53 +08:00

266 lines
8.5 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 "numkeydia.h"
#include "ui_numkeydia.h"
#include <QDebug>
#include <QFile>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QPushButton>
#include <QShortcut>
#include <QTextStream>
// --- 私有类定义 ---
class NumKeyDiaPrivate {
Q_DECLARE_PUBLIC(NumKeyDia)
public:
NumKeyDiaPrivate(NumKeyDia *q) : q_ptr(q) {}
// 成员变量移入 D-pointer
Ui::NumKeyDia *ui = nullptr;
QString value;
QPoint m_point;
bool m_firstInputFlag = true;
enum class InputPage { NumberPage, SymbolPage };
InputPage m_inputPage = InputPage::NumberPage;
// 辅助函数
void setInputPage(InputPage page);
void refreshInputButtons();
void configureInputButton(QPushButton *button, const QString &label,
const QString &value, bool enabled, bool isModeSwitch = false);
void loadStyleSheet();
private:
NumKeyDia *q_ptr; // 反向指针
};
// --- 私有类逻辑实现 ---
void NumKeyDiaPrivate::loadStyleSheet() {
QFile file(QStringLiteral(":/commonWidget.qss"));
if (file.open(QFile::ReadOnly | QFile::Text)) {
QTextStream stream(&file);
q_ptr->setStyleSheet(stream.readAll());
}
}
void NumKeyDiaPrivate::setInputPage(InputPage page) {
m_inputPage = page;
refreshInputButtons();
}
void NumKeyDiaPrivate::refreshInputButtons() {
if (m_inputPage == InputPage::NumberPage) {
configureInputButton(ui->btn_1, "1", "1", true);
configureInputButton(ui->btn_2, "2", "2", true);
configureInputButton(ui->btn_3, "3", "3", true);
configureInputButton(ui->btn_4, "4", "4", true);
configureInputButton(ui->btn_5, "5", "5", true);
configureInputButton(ui->btn_6, "6", "6", true);
configureInputButton(ui->btn_7, "7", "7", true);
configureInputButton(ui->btn_8, "8", "8", true);
configureInputButton(ui->btn_9, "9", "9", true);
configureInputButton(ui->btn_sub, "#+=", "", true, true);
configureInputButton(ui->btn_0, "0", "0", true);
configureInputButton(ui->pushButton_dot, ".", ".", true);
} else {
configureInputButton(ui->btn_1, "/", "/", true);
configureInputButton(ui->btn_2, "-", "-", true);
configureInputButton(ui->btn_3, ":", ":", true);
QString deg = QChar(0x00B0);
configureInputButton(ui->btn_4, deg, deg, true);
configureInputButton(ui->btn_5, "'", "'", true);
configureInputButton(ui->btn_6, "\"", "\"", true);
configureInputButton(ui->btn_7, ".", ".", true);
configureInputButton(ui->btn_8, "_", "_", true);
configureInputButton(ui->btn_9, "@", "@", true);
configureInputButton(ui->btn_sub, "123", "", true, true);
configureInputButton(ui->btn_0, "+", "+", true);
configureInputButton(ui->pushButton_dot, ",", ",", true);
}
}
void NumKeyDiaPrivate::configureInputButton(QPushButton *button, const QString &label,
const QString &value, bool enabled, bool isModeSwitch) {
if (!button) return;
button->setText(label);
button->setEnabled(enabled);
button->setProperty("inputValue", value);
button->setProperty("isModeSwitch", isModeSwitch);
}
// --- 公共类实现 ---
NumKeyDia *NumKeyDia::singleton = nullptr;
NumKeyDia::NumKeyDia(QWidget *parent)
: QDialog(parent)
, d_ptr(new NumKeyDiaPrivate(this)) // 初始化 d_ptr
{
Q_D(NumKeyDia);
if (!singleton) singleton = this;
Q_INIT_RESOURCE(NumKeyBoard);
d->ui = new Ui::NumKeyDia;
d->ui->setupUi(this);
d->loadStyleSheet();
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
d->ui->lineEdit_input->setFocusPolicy(Qt::StrongFocus);
auto btnList = d->ui->widget_input->findChildren<QPushButton *>();
for (auto *btn : btnList) {
connect(btn, &QPushButton::clicked, this, &NumKeyDia::btn_input_clicked);
btn->setFocusPolicy(Qt::NoFocus);
// 数字和符号按钮只负责屏幕点按输入,不参与对话框默认确认键竞争。
btn->setAutoDefault(false);
btn->setDefault(false);
}
// 物理键盘 Enter 应默认完成输入;其余操作按钮关闭 autoDefault
// 避免 Qt 把确认键派发到退格/清空等最近获得焦点的按钮。
d->ui->btn_ok->setAutoDefault(true);
d->ui->btn_ok->setDefault(true);
d->ui->btn_back->setAutoDefault(false);
d->ui->btn_clear->setAutoDefault(false);
d->ui->btn_cancel->setAutoDefault(false);
auto *okReturnShortcut = new QShortcut(QKeySequence(Qt::Key_Return), this);
connect(okReturnShortcut, &QShortcut::activated, this, &NumKeyDia::on_btn_ok_clicked);
auto *okEnterShortcut = new QShortcut(QKeySequence(Qt::Key_Enter), this);
connect(okEnterShortcut, &QShortcut::activated, this, &NumKeyDia::on_btn_ok_clicked);
d->ui->toolButton_ico->installEventFilter(this);
d->ui->label_appInfo->installEventFilter(this);
d->ui->btn_clear->setText(QStringLiteral("<"));
d->setInputPage(NumKeyDiaPrivate::InputPage::NumberPage);
}
NumKeyDia::~NumKeyDia() {
if (singleton == this) singleton = nullptr;
// QScopedPointer 会自动删除 d_ptr,但 Ui 需手动销毁(如果没设置 parent)
Q_D(NumKeyDia);
delete d->ui;
}
NumKeyDia* NumKeyDia::instance() {
if(!singleton)
singleton = new NumKeyDia;
return singleton;
}
bool NumKeyDia::eventFilter(QObject *, QEvent *event) {
Q_D(NumKeyDia);
if (event->type() == QEvent::MouseButtonPress) {
auto *mouseEvent = static_cast<QMouseEvent *>(event);
d->m_point = mouseEvent->globalPos() - frameGeometry().topLeft();
} else if (event->type() == QEvent::MouseMove) {
auto *mouseEvent = static_cast<QMouseEvent *>(event);
move(mouseEvent->globalPos() - d->m_point);
}
return false;
}
// 数字键盘物理确认键入口:直接收口到 OK,避免 QLineEdit 或按钮默认行为把 Enter 解释成其它操作。
void NumKeyDia::keyPressEvent(QKeyEvent *event) {
if (event && (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) {
on_btn_ok_clicked();
event->accept();
return;
}
QDialog::keyPressEvent(event);
}
void NumKeyDia::setValue(const QString &value) {
Q_D(NumKeyDia);
d->value = value;
d->setInputPage(NumKeyDiaPrivate::InputPage::NumberPage);
d->ui->lineEdit_input->setFocus();
d->ui->lineEdit_input->setText(value);
d->ui->lineEdit_input->setCursorPosition(d->ui->lineEdit_input->text().size());
d->m_firstInputFlag = true;
}
QString &NumKeyDia::getValue() {
Q_D(NumKeyDia);
return d->value;
}
void NumKeyDia::on_btn_ok_clicked() {
Q_D(NumKeyDia);
QString res = d->ui->lineEdit_input->text();
d->value = res.isEmpty() ? "0" : res;
closeKeyBoard();
}
void NumKeyDia::on_btn_cancel_clicked() {
closeKeyBoard();
}
void NumKeyDia::on_btn_clear_clicked() {
Q_D(NumKeyDia);
d->m_firstInputFlag = false;
int pos = d->ui->lineEdit_input->cursorPosition();
d->ui->lineEdit_input->setCursorPosition(qMax(0, pos - 1));
d->ui->lineEdit_input->setFocus();
}
void NumKeyDia::on_btn_back_clicked() {
Q_D(NumKeyDia);
d->m_firstInputFlag = false;
int index = d->ui->lineEdit_input->cursorPosition();
QString text = d->ui->lineEdit_input->text();
if (index > 0) {
text.remove(index - 1, 1);
d->ui->lineEdit_input->setText(text);
d->ui->lineEdit_input->setCursorPosition(index - 1);
}
d->ui->lineEdit_input->setFocus();
}
void NumKeyDia::btn_input_clicked() {
Q_D(NumKeyDia);
auto *btn = qobject_cast<QPushButton *>(sender());
if (!btn) return;
if (btn->property("isModeSwitch").toBool()) {
auto nextPage = (d->m_inputPage == NumKeyDiaPrivate::InputPage::NumberPage)
? NumKeyDiaPrivate::InputPage::SymbolPage
: NumKeyDiaPrivate::InputPage::NumberPage;
d->setInputPage(nextPage);
d->ui->lineEdit_input->setFocus();
return;
}
if (d->m_firstInputFlag) {
d->ui->lineEdit_input->clear();
d->m_firstInputFlag = false;
}
QString input = btn->property("inputValue").toString();
if (input.isEmpty()) return;
int index = d->ui->lineEdit_input->cursorPosition();
QString text = d->ui->lineEdit_input->text();
text.insert(index, input);
d->ui->lineEdit_input->setText(text);
d->ui->lineEdit_input->setFocus();
d->ui->lineEdit_input->setCursorPosition(index + input.size());
}
void NumKeyDia::closeKeyBoard() {
this->close();
}
namespace KeyBoard {
NumKeyDia *app() {
return NumKeyDia::instance();
}
}