常见的网络登录界面一般包括用户名 Lable 和编辑框,密码 Label 和编辑框,是否保存密码的 Check 按钮,以及确定登录和退出按钮组成,界面设计如下:
一般的登录流程如下:用户输入用户名和密码,有的可能会勾选保存密码选项;然后点击确定按钮向服务器发出登录请求;服务器收到请求后与数据库中存储的记录比较,存在则允许用户登入系统;客户端在收到确认后先将本次登录计入存入本地文件或数据库,然后开始加载相关内容或服务。
所以在后程序需要模拟服务器验证和用户输入记录缓存的功能。
明白基本流程后,下面介绍一下程序设计。程序界面实现类为QLogInWindow,头文件:
#ifndef QLOGINWINDOW_H
#define QLOGINWINDOW_H
#include
class QLineEdit;
class QPushButton;
class QCheckBox;
class QLogInWindow : public QMainWindow
{
Q_OBJECT
public:
QLogInWindow(QWidget *parent = 0);
~QLogInWindow() {}
private:
void createConnection();//初始化数据库
bool CheckUser(const QString&, const QString&);//用户校验
void SaveEntrytoFile(const QString&, const QString&);//保存登录记录到本地
//响应事件
public slots:
void onOkButtonClicked();
void onKeyboardButtonPressed();
void onKeyboardButtonReleased();
void onPasswdChanged(const QString&);
private:
QLineEdit *user_entry;//用户名
QLineEdit *passwd_entry;//密码
QPushButton* m_EyeButton;//密码显示或隐藏按钮
QCheckBox *rememberPSW; //是否记住密码
};
#endif // QLOGINWINDOW_H
该类的设计遵循登录界面的基本结构,slot 函数分别对应确定按钮和密码显示控制按钮。
实现:
#include "qloginwindow.h"
// For Debuging
#include <QDebug>
#include <QDate>
#include <QLabel>
#include <QLayout>
#include <QPushButton>
#include <QCheckBox>
#include <QLineEdit>
#include <QMessageBox>
#include <QRegExpValidator>
// For SQL
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlDriver>
QLogInWindow::QLogInWindow(QWidget *parent) : QMainWindow(parent)
{
QWidget *w = new QWidget(this);
this->setCentralWidget(w);
this->setWindowTitle("Log In Demo");
QGridLayout *grid = new QGridLayout(w);
user_entry = new QLineEdit(w);
user_entry->setPlaceholderText("User name");
passwd_entry = new QLineEdit(w);
passwd_entry->setPlaceholderText("Password");
passwd_entry->setEchoMode(QLineEdit::Password);//實現網頁登錄時的眼睛按鈕
passwd_entry->setContextMenuPolicy(Qt::NoContextMenu);//禁止右鍵菜單
//密碼顯示或隱藏提示按鈕
m_EyeButton = new QPushButton();
m_EyeButton->setObjectName("pEyeButton");
m_EyeButton->setFixedSize(QSize(16, 16));
m_EyeButton->setCursor(QCursor(Qt::PointingHandCursor));
m_EyeButton->setIcon(QIcon(":/Icon/Images/eye-close.png"));
m_EyeButton->setVisible(false);
QHBoxLayout* passwordEditLayout = new QHBoxLayout();
passwordEditLayout->addStretch();
passwordEditLayout->addWidget(m_EyeButton);
passwordEditLayout->setSpacing(0);
passwordEditLayout->setContentsMargins(0, 0, 8, 0);
passwd_entry->setLayout(passwordEditLayout);
QRegExp regx("^[^@$%#&^*|/?!~`\'\"]+$");
if(!regx.isValid()){
QString str = regx.errorString();
qDebug() << "Date:" << QDate::currentDate() <<
", Error:" << str;
}
QValidator *validator = new QRegExpValidator(regx, passwd_entry);
passwd_entry->setValidator(validator);//如何模仿 Windows 當輸入包含特殊符號時的提示功能,不能跳过
grid->addWidget(new QLabel("Username", w), 0, 0, 0);
grid->addWidget(new QLabel("Password", w), 1, 0, 0);
grid->addWidget(user_entry, 0, 1, 0);
grid->addWidget(passwd_entry, 1, 1, 0);
rememberPSW = new QCheckBox("记住密码", w);
rememberPSW->setChecked(false);
grid->addWidget(rememberPSW, 2, 0, Qt::AlignLeft);//是否记忆密码,未实现
QPushButton *OkButton = new QPushButton("Ok", w);
grid->addWidget(OkButton, 3, 0, Qt::AlignCenter);
QPushButton *CancleButton = new QPushButton("Cancle", w);
grid->addWidget(CancleButton, 3, 1, Qt::AlignCenter);
OkButton->setDefault(true); //设置默认 OK 按钮选中
connect(OkButton, SIGNAL(clicked(bool)), this, SLOT(onOkButtonClicked()));
connect(CancleButton, SIGNAL(clicked(bool)), this, SLOT(close()));
connect(passwd_entry, SIGNAL(returnPressed()), this, SLOT(onOkButtonClicked()));
connect(m_EyeButton, SIGNAL(pressed()), this, SLOT(onKeyboardButtonPressed()));
connect(m_EyeButton, SIGNAL(released()), this, SLOT(onKeyboardButtonReleased()));
connect(passwd_entry, SIGNAL(textEdited(QString)), this, SLOT(onPasswdChanged(QString)));
// Init database
createConnection();
}
void QLogInWindow::createConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
if (!db.open()) {
qFatal("Cannot open database");
return;
}
// We store to query.
QSqlQuery query;
query.exec("create table User (name TEXT NOT NULL, passwd TEXT NOT NULL, primary key(name))");
query.exec("insert into User values('root', 'alpine')");
query.exec("insert into User values('mobile', 'cherry')");
return;
}
bool QLogInWindow::CheckUser(const QString &user, const QString &passwd)
{
QString sql = QString("select name,passwd from User where name='%1' and passwd='%2'").arg(user).arg(passwd);
qDebug() << sql;
QSqlQuery query;
bool ret = query.exec(sql);
if(!ret) {
qFatal("Failed to query database");
return false;
}
while (query.next()) {
qDebug() << "Record found:" << query.value("name").toString() << query.value("passwd").toString();
return true;
}
return false;
}
void QLogInWindow::SaveEntrytoFile(const QString &user, const QString &passwd)
{
if(rememberPSW->isChecked()) {
(void)user;
(void)passwd;
//将登陆记录存入本地文件,未实现
}
}
void QLogInWindow::onOkButtonClicked()
{
QString user = user_entry->text();
QString passwd = passwd_entry->text();
if(CheckUser(user, passwd)) {
int ret = QMessageBox::information(this, "Welcome", "Welcome to Log in",
QMessageBox::Ok);
switch(ret) {
case QMessageBox::Ok:
SaveEntrytoFile(user, passwd);
close();
default:
break;
}
} else {
QMessageBox::warning(this, "Warnning", "User doesn't exist or wrong password",
QMessageBox::Ok);
passwd_entry->selectAll();
}
}
void QLogInWindow::onPasswdChanged(const QString &text)
{
if(text.isNull()){
m_EyeButton->setVisible(false);
} else {
m_EyeButton->setVisible(true);
}
}
void QLogInWindow::onKeyboardButtonPressed()
{
m_EyeButton->setIcon(QIcon(":/Icon/Images/eye-open.png"));
passwd_entry->setEchoMode(QLineEdit::Normal);
}
void QLogInWindow::onKeyboardButtonReleased()
{
m_EyeButton->setIcon(QIcon(":/Icon/Images/eye-close.png"));
passwd_entry->setEchoMode(QLineEdit::Password);
}
界面布局采用 QGridLayout,界面和数据库的初始化在该类的构造函数中完成,各个响应函数也都大部分完成,这里用两处没有实现:
第一,当用户输入特殊字符,如“@,%,*”,我希望能像 Windows 系统那样弹出提示框。
第二,将登录记录存入本地功能未实现。
另外,在添加数据库模块时,需要修改 pro 文件,在 pro 文件中添加如下内容:
QT += core gui sql
!contains(sql-drivers, sqlite): QTPLUGIN += qsqlite
关于密码框的眼睛小图标,我直接从 Windows 的登录界面抠的图,希望大家不要见怪。
执行效果:
程序不足之处欢迎指点。
参考链接:
Qt 之 模仿 QQ登陆界面——样式篇
正则表达式
QPushButton 响应回车 设置默认按钮