Fdog系列:使用Qt模仿QQ实现登录界面到主界面,功能篇。
Posted 花狗Fdog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fdog系列:使用Qt模仿QQ实现登录界面到主界面,功能篇。相关的知识,希望对你有一定的参考价值。
文章目录
一. 前言
Fdog系列已写目录:
Fdog系列(一):思来想去,不如写一个聊天软件,那就从仿QQ注册页面开始吧。
Fdog系列(二):html写完注册页面之后怎么办,用java写后台响应呀。
Fdog系列(三):使用腾讯云短信接口发送短信,数据库写入,部署到服务器,web收尾篇。
Fdog系列(四):使用Qt框架模仿QQ实现登录界面,界面篇。
Fdog系列(五):使用Qt模仿QQ实现登录界面到主界面,功能篇。 当前篇
读完该篇,你将学会:
如何保存登录数据
实现是否记住密码
如何获取本地数据
登录界面中出现的下拉框
从下拉列表框删除账号
改变选项,实时显示
其中下拉框的自定义比较复杂,我看到有网友在评论区问了如何实现,别急,它来了!看完本文,你将学会他。
同时完整项目代码已上传github:Fdog即时通讯软件 求星星!
二. 正文
1. 如何保存第一次登录数据
先来分析一下:
要保存的数据,1.头像 2.账号 3.密码 4.是否记住密码,并且第三项密码依赖于第四项用户是否勾选记住密码。
如何保存数据,给大家提供两种方法:1.使用了文本保存,2.使用ini配置文件保存。这两种方法都是可以的。为了方便,这里使用文本保存,如果想使用ini保存,可以参考这篇:QT学习笔记之读取INI文件
文件存放的位置,这里使用绝对路径是不明智的,应当使用相对地址,思路是获取可执行文件的目录,然后在其目录至上创建用户文件。
用户文件结构:创建FdogUserFile文件夹,再创建以用户账号为名的文件夹,这个文件夹包括图片文件和一个文本文件,图片文件就是头像,也是以用户账号命名,文本文件命名为data,里面存放账号和密码,这里有一个格式,第一行是账号,第二行是密码,当第二行为空时,说明用户没有选择记住密码。
应当注意的是这里不应该重复创建文件,应有一个判断,判断当前用户信息文件是否创建,若不存在则创建,若存在则更新即可。
差点忘了还有我们数据库的事,在这一切之前,应当将用户和密码和数据库数据对比,如果匹配,就从服务器下载头像和执行上面的内容。
下面来代码实现这一构想,现在假设照片已经存在服务器,例如当你输入网址:https://www.fdogcsdn.cn/img/10001.jpg
网页将显示一张图片。
至于如何让网页显示图片,会在下面写出,现在只需要考虑如何用代码实现下载图片和与数据库内容做做对比。
创建一个数据库类:usersql
#include<QNetworkAccessManager>
#include<QNetworkReply>
#include<QPixmap>
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
//上面三行防止中文乱码
class Usersql
{
private:
QSqlDatabase dbconn;//连接数据库
QSqlQuery query; //查询操作
QString account; //账号
QString passwd; //密码
QString iconurl; //地址
QPixmap icon; //头像
public:
void conndata(); //连接数据库
bool queryuser(QString user,QString password); //查询是否有该账户
QPixmap geticonurl(QString url);//根据地址网上下载图片
QPixmap getPixmapIcon(QString url);//url为账号,通过账号获取头像地址
};
void Usersql::conndata()
{
if(QSqlDatabase::contains(QSqlDatabase::defaultConnection))
{
this->dbconn = QSqlDatabase::database(QSqlDatabase::defaultConnection);
}
else
{
this->dbconn = QSqlDatabase::addDatabase("Qmysql");
}
this-> dbconn.setHostName("0.0.0.0");//主机名字 也是服务器ip 如果使用本地数据库测试,则使用127.0.0.1
this-> dbconn.setDatabaseName("fdogsql");//数据库名字
if(this->dbconn.open("root", "111111")) //用户名 密码
{
//如果判断为真,则连接成功
//qDebug()<<"success";
}
this->query = (QSqlQuery)this->dbconn; //进行绑定 此后可以使用query对象对数据库进行操作。
}
bool Usersql::queryuser(QString user, QString password)
{
this->query.exec("select * from user");
while(query.next())
{
//遍历账户 value中的值代表字段,0就是第一个,1就是第二个
qDebug()<<this->query.value(0).toString();
if(user==(this->query.value(0).toString()))
{
if(password==(this->query.value(3).toString()))
{
this->iconurl = this->query.value(5).toString();
qDebug()<<"该账户存在";
return true;
}
else
{
qDebug()<<"该账户不存在";
return false;
}
}
}
return false;
}
QPixmap Usersql::geticonurl(QString url1)
{
this->iconurl = url1;
QUrl url(this->iconurl);
qDebug()<<url;
QNetworkAccessManager manager;
QEventLoop loop;
// qDebug() << "Reading picture form " << url;
QNetworkReply *reply = manager.get(QNetworkRequest(url));
//请求结束并下载完成后,退出子事件循环
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
//开启子事件循环
loop.exec();
QByteArray jpegData = reply->readAll();
this->icon.loadFromData(jpegData);
return icon;
}
QPixmap Usersql::getPixmapIcon(QString url)
{
QString strurl;
//数据库查询该帐户
this->query.exec("select * from user");
while(query.next())
{
//遍历账户
if(url==(this->query.value(0).toString()))
{
strurl = this->query.value(5).toString();
}
}
qDebug()<<strurl;
QPixmap a = geticonurl(strurl);
a=this->icon.scaled(QSize(a.width(), a.height()), Qt::IgnoreAspectRatio);
a=PixmapToRound(a, a.width()/2);
return a;
}
然后来看下当点击登录按钮执行的代码
void Login::on_pushButton_clicked()
{ //ui->lineEdit_2是账号文本框 ui->lineEdit是密码文本框
sqconn.conndata();//连接数据库
bool isuser = sqconn.queryuser(ui->lineEdit_2->text(),ui->lineEdit->text());//输入内容查询
//判断用户是否存在
if(isuser)
{
//只获取账号
QString account = ui->lineEdit_2->text(); //账户
this->sqconn.queryUserInfo(account);//根据账户获取昵称,密码(如果用户选择记住密码,则保存密码),头像
QString name = sqconn.getName();
QString passwd="";
if(ui->checkBox_2->isChecked())//判断用户是否保存密码
{
passwd = sqconn.getPasswd();
}
QPixmap icon = sqconn.getIcon();
//获取程序当前运行目录
QString fileName = QCoreApplication::applicationDirPath();
//用户目录
QString add = "//..//FdogUserFile";
//创建用户文件夹
fileName = fileName + add +QString("//%1").arg(account);
//信息保存
QDir * file = new QDir;
//文件夹是否存在,若存在则表示信息已经存在,只需要更新内容即可。
bool exist_1 = file->exists(fileName);
if(exist_1)
{
//qDebug()<<"创建";
QFile file(fileName +"//data.txt");
qDebug()<<fileName +"//data.txt";
if(file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate))
{
//qDebug()<<"txt文件创建成功";
}
QTextStream stream(&file);
//写入
if(passwd=="")stream<<name;
else stream<<name<<"\\n"<<passwd;
//qDebug()<<"tup:"<<account;
icon.save(fileName+QString("//%1.jpg").arg(account),"JPG");
file.close();
}
else
{ //如果不存在则创建
bool ok = file->mkpath(fileName);
if(ok)
{
//qDebug()<<"创建";
QFile file(fileName +"//data.txt");
qDebug()<<fileName +"//data.txt";
if(file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate))
{
//qDebug()<<"txt文件创建成功";
}
QTextStream stream(&file);
if(passwd=="")stream<<name;
else stream<<name<<"\\n"<<passwd;
icon.save(fileName+QString("//%1.jpg").arg(account),"JPG");
file.close();
}
else
{
qDebug()<<"未创建成功";
}
}
this->hide();//隐藏登录窗口
systemtrayicon->hide();//隐藏系统托盘
//初始化主界面 w是在头文件定义的主界面类,这里只是作为演示。
w = new MainWindow(account);
//显示主界面
w->show();
//显示系统托盘图标
w->showicon();
}
else
{
//该用户不存在
}
}
当登录账号后,创建效果:
当然使用明文保存密码是不安全的,可以参考之前我写的一篇加密:非对称性加密算法——RSA算法原理及C++实现
然后来说如何让服务器正确显示照片,在服务器根目录创建一个fdogpoject/fdog/img的路径,在img文件夹下存放我们的照片,当然这样,我们是无法通过https://www.fdogcsdn.cn/img/10001.jpg来显示图片的,还需要改一点东西。
我是使用tomcat搭建的服务,所以在conf文件夹下修改server.xml文件,添加:
<Context reloadable="true" docBase="/fdogpoject/fdog/img/" path="/img"/>
然后重启tomcat就可以访问了。
2. 如何获取已经登录过的账号信息,并完成自定义下列框
这一步相对于如何保存信息已经简单了许多, 只需要将头像和文件内容显示在下拉列表框即可。
登录界面类:
class Login : public QWidget
{
private:
QVector<int> infoListsign;
QSignalMapper * myMapper;
QStringList infoList; //用户账号
QStringList infopasswd; //用户密码
QStringList icon; //头像保存地址
public:
explicit Login(QWidget *parent = 0);//构造函数
QStringList GetDirNameList(const QString &strDirpath);//用于获取用户文件下所有账号(实际上是获取目录下所有文件名)
};
Login::Login(QWidget *parent) :
QWidget(parent),
ui(new Ui::Login)
{
ui->setupUi(this);
//获取exe运行目录
QString fileName1 = QCoreApplication::applicationDirPath()+"//..//FdogUserFile";
//获取目录
infoList = GetDirNameList(fileName1);
//加载自定义的下拉列表框
m_AccountList = new QListWidget(this);
m_AccountList->setFocusPolicy(Qt::NoFocus);
ui->comboBox->setModel(m_AccountList->model());
ui->comboBox->setView(m_AccountList);
for(int i =0;i<infoList.size();i++)
{
//获取帐号
QString local_account = infoList.at(i);
//获取昵称
QString local_name;
//获取密码
QString local_passwd;
//获取头像
QString ic = fileName1+QString("//%1//%2.jpg").arg(infoList.at(i)).arg(infoList.at(i));
this->icon.append(ic);
QIcon local_icon(ic);
QFile file_my(fileName1+QString("//%1//data.txt").arg(infoList.at(i)));
if(!file_my.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug()<<"文件打开失败"<<endl;
}
this->ispasswd = false;
while(!file_my.atEnd())
{
infopasswd.append("");
QByteArray line = file_my.readLine();
QString str(QString::fromLocal8Bit(line.data()));
//qDebug()<< str;
if(this->ispasswd)
{
//还应该查看是否有密码存在,如果有则读取,并显示勾中
infopasswd.insert(i,str);
//qDebug()<<"有密码"<<str;
local_passwd.append(str);
this->ispasswd =false;
}
else
{
local_name.append(str);
this->ispasswd =true;
}
qDebug()<<infopasswd;
}
QHBoxLayout *horLayout = new QHBoxLayout();//水平布局
QLabel * la = new QLabel();
QString s = ic;
la->setStyleSheet(QString("border-image: url(%1);border-radius:17px;").arg(s));
la->setFixedSize(34,34);
QLabel * la2 = new QLabel(QString("%1\\n%2").arg(local_name.left(local_name.length()-1),local_account));
QPushButton * b1 = new QPushButton();
b1->setFixedSize(32,32);
b1->setStyleSheet("QPushButton{background:rgba(200,200,200,0);border-style:solid;border-image: url(:/lib/delete.png);}"
"QPushButton:hover{background:rgba(200,200,200,0);border-style:solid;border-image: url(:/lib/delete2.png);}");
horLayout->addWidget(la);
horLayout->addWidget(la2);
horLayout->addWidget(b1);
QWidget *widget =new QWidget(this);
widget->setLayout(horLayout);
QListWidgetItem * Listitem = new QListWidgetItem(m_AccountList);
m_AccountList->setItemWidget(Listitem,widget);
}
}
QStringList Login::GetDirNameList(const QString &strDirpath)
{
以上是关于Fdog系列:使用Qt模仿QQ实现登录界面到主界面,功能篇。的主要内容,如果未能解决你的问题,请参考以下文章
Fdog系列:利用Qt通过服务端进行客户端与客户端通信(资料少,建议收藏)