319 lines
7.9 KiB
C++
319 lines
7.9 KiB
C++
#include "dialogcontrolpassword.h"
|
|
#include "ui_dialogcontrolpassword.h"
|
|
|
|
#include <QFont>
|
|
#include <QGridLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QKeyEvent>
|
|
#include <QLabel>
|
|
#include <QList>
|
|
#include <QPushButton>
|
|
#include <QShowEvent>
|
|
#include <QSizePolicy>
|
|
#include <QTimer>
|
|
|
|
namespace {
|
|
|
|
const char* kDigitBoxStyleEmpty =
|
|
"color: rgb(221, 225, 233);"
|
|
"background-color: rgb(47, 48, 52);"
|
|
"border: 1px solid rgb(70, 72, 78);"
|
|
"border-radius: 4px;";
|
|
|
|
const char* kDigitBoxStyleFilled =
|
|
"color: rgb(221, 225, 233);"
|
|
"background-color: rgb(60, 120, 180);"
|
|
"border: 1px solid rgb(80, 140, 200);"
|
|
"border-radius: 4px;";
|
|
|
|
const char* kKeypadButtonStyle =
|
|
"QPushButton {"
|
|
" background-color: rgb(47, 48, 52);"
|
|
" color: rgb(221, 225, 233);"
|
|
" border: 1px solid rgb(70, 72, 78);"
|
|
" border-radius: 4px;"
|
|
"}"
|
|
"QPushButton:hover {"
|
|
" background-color: rgb(70, 72, 78);"
|
|
"}"
|
|
"QPushButton:pressed {"
|
|
" background-color: rgb(40, 100, 160);"
|
|
"}";
|
|
|
|
QPushButton* MakeKeypadButton(QWidget* parent, const QString& text)
|
|
{
|
|
auto* button = new QPushButton(text, parent);
|
|
button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
button->setMinimumSize(90, 72);
|
|
button->setFocusPolicy(Qt::NoFocus);
|
|
button->setStyleSheet(QString::fromLatin1(kKeypadButtonStyle));
|
|
QFont font = button->font();
|
|
font.setPointSize(22);
|
|
font.setBold(true);
|
|
button->setFont(font);
|
|
return button;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
DialogControlPassword::DialogControlPassword(QWidget* parent)
|
|
: QDialog(parent)
|
|
, ui(new Ui::DialogControlPassword)
|
|
{
|
|
ui->setupUi(this);
|
|
setModal(true);
|
|
setWindowModality(Qt::ApplicationModal);
|
|
setFixedSize(520, 720);
|
|
setFocusPolicy(Qt::StrongFocus);
|
|
if (ui->btnOK) {
|
|
ui->btnOK->setFocusPolicy(Qt::NoFocus);
|
|
}
|
|
if (ui->btnCancel) {
|
|
ui->btnCancel->setFocusPolicy(Qt::NoFocus);
|
|
}
|
|
ApplyUiFont();
|
|
if (ui->label_title) {
|
|
QFont titleFont = ui->label_title->font();
|
|
titleFont.setPointSize(20);
|
|
titleFont.setBold(true);
|
|
ui->label_title->setFont(titleFont);
|
|
}
|
|
BuildDigitBoxes();
|
|
BuildKeypad();
|
|
UpdateOkEnabled();
|
|
}
|
|
|
|
DialogControlPassword::~DialogControlPassword()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
void DialogControlPassword::SetTitle(const QString& title)
|
|
{
|
|
const QString windowTitle = title.isEmpty()
|
|
? QStringLiteral("控制密码")
|
|
: title;
|
|
setWindowTitle(windowTitle);
|
|
if (ui && ui->label_title) {
|
|
ui->label_title->setText(windowTitle);
|
|
}
|
|
}
|
|
|
|
QString DialogControlPassword::Password() const
|
|
{
|
|
return m_password;
|
|
}
|
|
|
|
void DialogControlPassword::SetError(const QString& text)
|
|
{
|
|
if (!ui || !ui->label_error) {
|
|
return;
|
|
}
|
|
ui->label_error->setText(text);
|
|
}
|
|
|
|
void DialogControlPassword::SetPasswordChecker(
|
|
const std::function<bool(const QString&)>& checker)
|
|
{
|
|
m_passwordChecker = checker;
|
|
}
|
|
|
|
void DialogControlPassword::on_btnOK_clicked()
|
|
{
|
|
TryAccept();
|
|
}
|
|
|
|
void DialogControlPassword::on_btnCancel_clicked()
|
|
{
|
|
reject();
|
|
}
|
|
|
|
void DialogControlPassword::ApplyUiFont()
|
|
{
|
|
QFont font;
|
|
font.setPointSize(16);
|
|
setFont(font);
|
|
const QList<QWidget*> widgets = findChildren<QWidget*>();
|
|
for (QWidget* widget : widgets) {
|
|
widget->setFont(font);
|
|
}
|
|
}
|
|
|
|
void DialogControlPassword::BuildDigitBoxes()
|
|
{
|
|
if (!ui || !ui->widget_digits) {
|
|
return;
|
|
}
|
|
|
|
auto* layout = new QHBoxLayout(ui->widget_digits);
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
layout->setSpacing(10);
|
|
m_digitLabels.clear();
|
|
m_digitLabels.reserve(kPasswordLength);
|
|
for (int i = 0; i < kPasswordLength; ++i) {
|
|
auto* digitLabel = new QLabel(ui->widget_digits);
|
|
digitLabel->setAlignment(Qt::AlignCenter);
|
|
digitLabel->setMinimumSize(56, 56);
|
|
QFont digitFont = digitLabel->font();
|
|
digitFont.setPointSize(22);
|
|
digitFont.setBold(true);
|
|
digitLabel->setFont(digitFont);
|
|
layout->addWidget(digitLabel);
|
|
m_digitLabels.append(digitLabel);
|
|
}
|
|
RefreshDigits();
|
|
}
|
|
|
|
void DialogControlPassword::BuildKeypad()
|
|
{
|
|
if (!ui || !ui->widget_keypad) {
|
|
return;
|
|
}
|
|
|
|
auto* layout = new QGridLayout(ui->widget_keypad);
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
layout->setHorizontalSpacing(12);
|
|
layout->setVerticalSpacing(12);
|
|
|
|
const int keys[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
|
for (int i = 0; i < 9; ++i) {
|
|
const int digit = keys[i];
|
|
QPushButton* button = MakeKeypadButton(
|
|
ui->widget_keypad,
|
|
QString::number(digit));
|
|
connect(button, &QPushButton::clicked, this, [this, digit]() {
|
|
AppendDigit(QChar('0' + digit));
|
|
});
|
|
layout->addWidget(button, i / 3, i % 3);
|
|
}
|
|
|
|
QPushButton* backButton = MakeKeypadButton(
|
|
ui->widget_keypad,
|
|
QStringLiteral("删除"));
|
|
connect(backButton, &QPushButton::clicked, this, [this]() {
|
|
RemoveLastDigit();
|
|
});
|
|
layout->addWidget(backButton, 3, 0);
|
|
|
|
QPushButton* zeroButton = MakeKeypadButton(
|
|
ui->widget_keypad,
|
|
QStringLiteral("0"));
|
|
connect(zeroButton, &QPushButton::clicked, this, [this]() {
|
|
AppendDigit(QLatin1Char('0'));
|
|
});
|
|
layout->addWidget(zeroButton, 3, 1);
|
|
|
|
QPushButton* clearButton = MakeKeypadButton(
|
|
ui->widget_keypad,
|
|
QStringLiteral("清空"));
|
|
connect(clearButton, &QPushButton::clicked, this, [this]() {
|
|
ClearPassword();
|
|
});
|
|
layout->addWidget(clearButton, 3, 2);
|
|
}
|
|
|
|
void DialogControlPassword::AppendDigit(QChar digit)
|
|
{
|
|
if (!digit.isDigit() || m_password.size() >= kPasswordLength) {
|
|
return;
|
|
}
|
|
m_password.append(digit);
|
|
SetError(QString());
|
|
RefreshDigits();
|
|
// 满 6 位后自动校验,正确关闭窗口,错误提示并清空。
|
|
if (m_password.size() == kPasswordLength) {
|
|
QTimer::singleShot(50, this, [this]() {
|
|
TryAccept();
|
|
});
|
|
}
|
|
}
|
|
|
|
void DialogControlPassword::RemoveLastDigit()
|
|
{
|
|
if (m_password.isEmpty()) {
|
|
return;
|
|
}
|
|
m_password.chop(1);
|
|
SetError(QString());
|
|
RefreshDigits();
|
|
}
|
|
|
|
void DialogControlPassword::ClearPassword()
|
|
{
|
|
if (m_password.isEmpty()) {
|
|
RefreshDigits();
|
|
return;
|
|
}
|
|
m_password.clear();
|
|
RefreshDigits();
|
|
}
|
|
|
|
void DialogControlPassword::RefreshDigits()
|
|
{
|
|
for (int i = 0; i < m_digitLabels.size(); ++i) {
|
|
QLabel* digitLabel = m_digitLabels[i];
|
|
if (!digitLabel) {
|
|
continue;
|
|
}
|
|
const bool filled = i < m_password.size();
|
|
digitLabel->setText(filled ? QStringLiteral("●") : QString());
|
|
digitLabel->setStyleSheet(QString::fromLatin1(
|
|
filled ? kDigitBoxStyleFilled : kDigitBoxStyleEmpty));
|
|
}
|
|
UpdateOkEnabled();
|
|
}
|
|
|
|
void DialogControlPassword::UpdateOkEnabled()
|
|
{
|
|
if (ui && ui->btnOK) {
|
|
ui->btnOK->setEnabled(m_password.size() == kPasswordLength);
|
|
}
|
|
}
|
|
|
|
void DialogControlPassword::TryAccept()
|
|
{
|
|
if (m_password.size() != kPasswordLength) {
|
|
SetError(QStringLiteral("请输入6位数字密码"));
|
|
return;
|
|
}
|
|
if (m_passwordChecker && !m_passwordChecker(m_password)) {
|
|
SetError(QStringLiteral("密码错误"));
|
|
ClearPassword();
|
|
return;
|
|
}
|
|
accept();
|
|
}
|
|
|
|
void DialogControlPassword::showEvent(QShowEvent* event)
|
|
{
|
|
QDialog::showEvent(event);
|
|
ClearPassword();
|
|
SetError(QString());
|
|
setFocus();
|
|
}
|
|
|
|
void DialogControlPassword::keyPressEvent(QKeyEvent* event)
|
|
{
|
|
if (!event) {
|
|
return;
|
|
}
|
|
if (event->key() == Qt::Key_Escape) {
|
|
reject();
|
|
return;
|
|
}
|
|
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
|
|
on_btnOK_clicked();
|
|
return;
|
|
}
|
|
if (event->key() == Qt::Key_Backspace) {
|
|
RemoveLastDigit();
|
|
return;
|
|
}
|
|
const QString text = event->text();
|
|
if (text.size() == 1 && text[0].isDigit()) {
|
|
AppendDigit(text[0]);
|
|
return;
|
|
}
|
|
QDialog::keyPressEvent(event);
|
|
}
|