当前位置: 首页 > news >正文

QT聊天项目DAY12

0.注册界面完善

1. 密码加密

#ifndef GLOBAL_H
#define GLOBAL_H
#include <QWidget>
#include <functional>
#include <QRegularExpression>
#include "QStyle"#include <memory>
#include <iostream>
#include <mutex>#include <QString>
#include <QSettings>using namespace std;// extern 声明此变量是在其他文件中定义的全局变量
extern function<void(QWidget*)> repolish;extern function<QString(QString)> xorString;			// 密码加密extern QString ConfigPath;								// 配置文件路径
extern QSettings* ConfigSettings;						// 配置文件对象#endif // GLOBAL_H
#include "Global.h"#include <QDir>// 初始化声明的全局变量
function<void(QWidget*)> repolish = [](QWidget* Widget)
{Widget->style()->unpolish(Widget);Widget->style()->polish(Widget);
};/* 密码加密 */
function<QString(QString)> xorString = [](QString input){QString result = input;int length = input.length();length %= 255;for (int i = 0; i < length; ++i){result[i] = QChar(static_cast<ushort>(input[i].unicode() ^ static_cast<ushort>(length)));}return result;};// 配置文件路径
QString ConfigPath = QDir::currentPath() + "/Config/Config.ini";// 管理配置文件对象
QSettings* ConfigSettings = new QSettings(ConfigPath, QSettings::IniFormat);

2. 添加定时按钮

点击获取验证码后需要让按钮显示倒计时,然后倒计时结束后才能再次点击

添加TimerBtn类

.h

#ifndef TIMERBTN_H
#define TIMERBTN_H#include <QPushButton>
#include <QTimer>class TimerBtn  : public QPushButton
{Q_OBJECTpublic:TimerBtn(QWidget *parent = 0);~TimerBtn();public:virtual void mouseReleaseEvent(QMouseEvent *event) override;private:QTimer *_timer = nullptr;int _counter = 0;
};
#endif // TIMERBTN_H

.cpp文件

#include "TimerBtn.h"
#include <QMouseEvent>
#include <QDebug>TimerBtn::TimerBtn(QWidget*parent): QPushButton(parent),_counter(10)
{_timer = new QTimer(this);connect(_timer, &QTimer::timeout, [this](){_counter--;if (_counter <= 0){_timer->stop();_counter = 10;setText(QString::fromLocal8Bit("获取"));setEnabled(true);										// 设置为可用return;}setText(QString::number(_counter));});
}TimerBtn::~TimerBtn()
{_timer->stop();
}void TimerBtn::mouseReleaseEvent(QMouseEvent * event)
{if (event->button() == Qt::LeftButton){qDebug() << "TimerBtn::mouseReleaseEvent";setEnabled(false);												// 设置为不可用_timer->start(1000);											// 启动定时器emit clicked();}QPushButton::mouseReleaseEvent(event);
}

将获取按钮提升为TimerBtm

3. 检测输入是否合理

3.1 枚举错误类型

在Enum.h中添加下列枚举

/* 标签错误类型 */
enum TipErr {TIP_SUCCESS = 0,TIP_EMAIL_ERR = 1,TIP_PWD_ERR = 2,TIP_CONFIRM_ERR = 3,TIP_PWD_CONFIRM = 4,TIP_VERIFY_ERR = 5,TIP_USER_ERR = 6
};

3.2 添加错误提示的接口

QMap<TipErr, QString> _TipErrs;																	// 错误提示void AddTipErr(TipErr err, const QString& tips);												// 添加错误提示void DelTipErr(TipErr err);																		// 清除错误提示/* 添加错误提示 */
void RegisterWidget::AddTipErr(TipErr err, const QString & tips)
{_TipErrs[err] = tips;ShowTipLabel(tips, "error");
}/* 清空错误提示 */
void RegisterWidget::DelTipErr(TipErr err)
{_TipErrs.remove(err);if (_TipErrs.isEmpty()){ui.Tip_Label->clear();return;}ShowTipLabel(_TipErrs.first(), "error");
}

3.3 绑定文本输入的回调检查

/* 检查输入是否合法 */
connect(ui.User_Edit, &QLineEdit::editingFinished, this, &RegisterWidget::CheckUserValid);
connect(ui.Email_Edit, &QLineEdit::editingFinished, this, &RegisterWidget::CheckEmailValid);
connect(ui.PassWord_Edit, &QLineEdit::editingFinished, this, &RegisterWidget::CheckPasswordValid);
connect(ui.Enter_Edit, &QLineEdit::editingFinished, this, &RegisterWidget::CheckEnsurePasswordValid);
connect(ui.Verify_Edit, &QLineEdit::editingFinished, this, &RegisterWidget::CheckVerifyCodeValid);

3.4 回调的实现

/* 检查用户名是否合法 */
bool RegisterWidget::CheckUserValid()
{if (ui.User_Edit->text().isEmpty()){AddTipErr(TipErr::TIP_USER_ERR, QString::fromLocal8Bit("用户名不能为空"));return false;}/* 一切正常则删除错误提示 */DelTipErr(TipErr::TIP_USER_ERR);return true;
}/* 检查邮箱是否合法 */
bool RegisterWidget::CheckEmailValid()
{QString emailText = ui.Email_Edit->text();// 邮箱地址的正则表达式QRegularExpression regex(R"((\w+)(\.|_)?(\w*)@(\w+)(\.(\w+))+)");bool match = regex.match(emailText).hasMatch();if (!match){AddTipErr(TipErr::TIP_EMAIL_ERR, QString::fromLocal8Bit("邮箱格式不正确"));return false;}/* 一切正常则删除错误提示 */DelTipErr(TipErr::TIP_EMAIL_ERR);return true;
}/* 检查密码是否合法 */
bool RegisterWidget::CheckPasswordValid()
{QString passText = ui.PassWord_Edit->text();if (passText.length() < 6 || passText.length() > 15){AddTipErr(TipErr::TIP_PWD_ERR, QString::fromLocal8Bit("密码长度必须在6-15位之间"));return false;}/* 密码长度至少6位 可以是字母、数字、特定的特殊字符 */QRegularExpression regExp("^[a-zA-Z0-9!@#$%^&*]{6,15}$");bool match = regExp.match(passText).hasMatch();if (!match){AddTipErr(TipErr::TIP_PWD_ERR, QString::fromLocal8Bit("不能包含非法字符"));return false;}/* 一切正常则删除错误提示 */DelTipErr(TipErr::TIP_PWD_ERR);return true;
}/* 检查确认密码是否合法 */
bool RegisterWidget::CheckEnsurePasswordValid()
{QString enterText = ui.Enter_Edit->text();if (ui.PassWord_Edit->text() != enterText){AddTipErr(TipErr::TIP_CONFIRM_ERR, QString::fromLocal8Bit("两次密码输入不一致"));return false;}/* 一切正常则删除错误提示 */DelTipErr(TipErr::TIP_CONFIRM_ERR);return true;
}/* 检查验证码是否合法 */
bool RegisterWidget::CheckVerifyCodeValid()
{QString verifyText = ui.Verify_Edit->text();if (verifyText.isEmpty()){AddTipErr(TipErr::TIP_VERIFY_ERR, QString::fromLocal8Bit("验证码不能为空"));return false;}/* 一切正常则删除错误提示 */DelTipErr(TipErr::TIP_VERIFY_ERR);return true;
}

当确认按钮刷新时,检查输入是否合法

/* 确认按钮点击 */
void RegisterWidget::OnConfirmButtonClicked()
{bool valid = CheckUserValid();if (!valid)return;valid = CheckEmailValid();if (!valid)return;valid = CheckPasswordValid();if (!valid)return;valid = CheckEnsurePasswordValid();if (!valid)return;valid = CheckVerifyCodeValid();if (!valid)return;

4. 隐藏和显示密码

4.1 QT样式表

#Enter_Visible[state='visible_hover']
{border-image: url(:/Chat/Images/visible_hover.png);
}

#PassWord_Visible[state='unvisible']
{border-image: url(:/Chat/Images/unvisible.png);
}#PassWord_Visible[state='unvisible_hover']
{border-image: url(:/Chat/Images/unvisible_hover.png);
}#PassWord_Visible[state='visible']
{border-image: url(:/Chat/Images/visible.png);
}#PassWord_Visible[state='visible_hover']
{border-image: url(:/Chat/Images/visible_hover.png);
}#Enter_Visible[state='unvisible']
{border-image: url(:/Chat/Images/unvisible.png);
}#Enter_Visible[state='unvisible_hover']
{border-image: url(:/Chat/Images/unvisible_hover.png);
}#Enter_Visible[state='visible']
{border-image: url(:/Chat/Images/visible.png);
}#Enter_Visible[state='visible_hover']
{border-image: url(:/Chat/Images/visible_hover.png);
}

4.2 重写ClickedLabel

一个Label有六种状态,普通状态,普通的悬浮状态,普通的点击状态,选中状态,选中的悬浮状态,选中的点击状态

当Label处于普通状态时,被点击后,切换为选中状态,再次点击又切换为普通状态

定义ClickLableState,包括两种状态,一个是普通状态,一个是选中状态。Label的六种状态都是基于这两种状态实现的

通过样式表来灵活切换标签的UI,只需要通过setProperty("state", str);设置对应的状态即可

然后自定义的控件只需要继承即可实现UI随着鼠标的进入离开以及点击时的切换

.h

#ifndef CLICKEDLABEL_H
#define CLICKEDLABEL_H#include <QLabel>
#include <QString>
#include "Enum.h"class ClickedLabel  : public QLabel
{Q_OBJECTpublic:ClickedLabel(QWidget *parent = 0);~ClickedLabel();public:virtual void mousePressEvent(QMouseEvent *event) override;virtual void enterEvent(QEvent *event) override;virtual void leaveEvent(QEvent *event) override;ClickLabelState GetState() const;signals:void clicked(void);private:void UpdateStyleSheet(QString str);													// 刷新样式private:QString _Normal;																	// 未选中QString _NormalHover;QString _NormalPress;QString _Selected;																	// 选中QString _SelectedHover;QString _SelectedPress;ClickLabelState _CurrState;															// 当前标签状态
};
#endif // CLICKEDLABEL_H

.cpp

#include "ClickedLabel.h"#include <QMouseEvent>
#include <QDebug>
#include "Global.h"ClickedLabel::ClickedLabel(QWidget *parent): QLabel(parent), _CurrState(ClickLabelState::Normal)
{_Normal = "unvisible";_NormalHover = "unvisible_hover";_NormalPress = "";_Selected = "visible";_SelectedHover = "visible_hover";_SelectedPress = "";UpdateStyleSheet(_Normal);
}ClickedLabel::~ClickedLabel()
{}/* 刷新样式 */
void ClickedLabel::UpdateStyleSheet(QString str)
{setProperty("state", str);repolish(this);update();
}/* 鼠标按下事件 */
void ClickedLabel::mousePressEvent(QMouseEvent * event)
{if (event->button() == Qt::LeftButton){if (_CurrState == ClickLabelState::Normal){qDebug() << "clicked , change to selected hover" << _SelectedHover;_CurrState = ClickLabelState::Selected;UpdateStyleSheet(_SelectedHover);}else{qDebug() << "clicked , change to normal hover" << _NormalHover;_CurrState = ClickLabelState::Normal;UpdateStyleSheet(_NormalHover);}emit clicked();}QLabel::mousePressEvent(event);
}/* 鼠标悬停进入事件 */
void ClickedLabel::enterEvent(QEvent* event)
{if (_CurrState == ClickLabelState::Normal){qDebug() << "enter , change to hover" << _NormalHover;UpdateStyleSheet(_NormalHover);}else{qDebug() << "enter , change to selected hover" << _SelectedHover;UpdateStyleSheet(_SelectedHover);}QLabel::enterEvent(event);
}/* 鼠标离开事件 */
void ClickedLabel::leaveEvent(QEvent* event)
{if (_CurrState == ClickLabelState::Normal){qDebug() << "leave , change to normal" << _Normal;UpdateStyleSheet(_Normal);}else{qDebug() << "leave , change to selected" << _Selected;UpdateStyleSheet(_Selected);}QLabel::leaveEvent(event);
}ClickLabelState ClickedLabel::GetState() const
{return _CurrState;
}

4.3 创建可视化控件

将该标签提升为自定义的控件

4.4 在注册窗口中绑定可视化控件的信号槽

/* 初始化可视化控件 */
ui.PassWord_Visible->setCursor(Qt::PointingHandCursor);
ui.Enter_Visible->setCursor(Qt::PointingHandCursor);
BindSlotsFromClickedLabel();
/* 绑定信号槽从ClickedLabel控件 */
void RegisterWidget::BindSlotsFromClickedLabel()
{/* 密码可见 */connect(ui.PassWord_Visible, &ClickedLabel::clicked, this, [this](){auto state = ui.PassWord_Visible->GetState();if (state == ClickLabelState::Normal){ui.PassWord_Edit->setEchoMode(QLineEdit::Password);}else if (state == ClickLabelState::Selected){ui.PassWord_Edit->setEchoMode(QLineEdit::Normal);}});connect(ui.Enter_Visible, &ClickedLabel::clicked, this, [this](){auto state = ui.Enter_Visible->GetState();if (state == ClickLabelState::Normal){ui.Enter_Edit->setEchoMode(QLineEdit::Password);}else if (state == ClickLabelState::Selected){ui.Enter_Edit->setEchoMode(QLineEdit::Normal);}});
}

4.5 注册成功的提示界面

首先添加两个标签,然后调整整体窗口布局为垂直布局,让两个标签水平居中,添加返回按钮并设置按钮最大最小高度为25,将按钮放置到窗口内,并设置窗口布局为水平

4.6 注册成功的界面切换和自动跳转登陆界面

4.7 绑定返回按钮和取消按钮的槽函数

4.8 在主窗口绑定登录界面和注册界面的切换

切换到注册界面时,先创建注册界面的对象,然后绑定信号方便后续切换回登陆界面

同理,切换回登录界面时,先创建登录界面的对象,然后绑定信号方便切换回注册界面

为什么不再构造函数中创建是因为,调用setCentralWidget会销毁别的闲置窗口,从注册界面再切回登录界面时,此时登陆界面就被销毁了,所以调用已销毁对象的槽函数,程序会崩溃

4.9 测试注册成功的逻辑

流程已跑通

相关文章:

  • Git企业级——进阶
  • 达梦数据库-学习-21-C 外部函数
  • 怎么判断一个Android APP使用了Cordova这个跨端框架
  • ubuntu设置开机不输密码笔记
  • 《STL--- vector的使用及其底层实现》
  • 会话管理有哪些
  • 【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之3D高斯椭球
  • 【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之协方差矩阵控制椭球
  • JavaScript篇:解密ES6的“藏宝图“:Set和Map的奇妙冒险
  • 基于注解的Sentinel限流熔断
  • Sentinel+OpenFeign实现服务熔断与降级:构建弹性微服务架构的核心实践
  • PET,Prompt Tuning,P Tuning,Lora,Qlora 大模型微调的简介
  • PyQt5安装,在Pycharm上配置以及使用教程
  • spring注解旁路问题讨论
  • Wkhtmltopdf使用
  • 端到端大语言模型微调技术 Demo 全流程详解(附完整模块说明)
  • 飞书知识问答产品测评:让企业玩转AI
  • C# TCP协议全面指南:从可靠传输到企业级高并发的深度实践​
  • 职业规划:动态迭代的系统化路径
  • C# Windows Forms应用程序-001
  • cms影视建站系统/视频互联网推广选择隐迅推
  • 单位做网站资料需要什么/自己怎么优化我网站关键词
  • 德州做网站公司排行/友情链接检索数据分析
  • 太原网站科技公司/网站设计制作哪家好
  • wordpress+程序优化/seo网站推广如何做
  • 如何申请网上商城/青岛设计优化公司