1. 前言
断断续续黑框框下的学生管理系统,也写了不下三次,总在黑框框下呆着也不是一回事,想挑战用qt做一个界面版的学生管理系统,至于为什么选用qt+C++,而不用C#之类的,是因为我目前学习C++,手头只接触了qt,所以想着挑战一下自己。从他人博客获取知识,为我所用,最后再输出到博客,供他人学习,这种感觉真的很棒。这几篇文章重在出效果,大牛勿喷,边学边做边发博,文中的代码可能不完整,我是拿出单个功能来说的,或许会出现错误,不用着急啦,需要用到的资源以及代码,我都会打包上传,如有需要的,可自行下载。
(相关资料图)
操作环境:
QT5.10.0 MySQL8.0.192. 效果图
2.1 大体
2.2 主界面
2.3 注册图
由于图片大小问题,具体操作就不录了,不过放心,都在代码里,嘿嘿。
3. 流程图
4. 代码实现
4.1 使用Mysql及邮箱发送
4.1.1 连接Mysql 并使用
为了方便,这里我用了Navicat Preminum 对MySQL进行可视化操作,我们在名为test的数据库下创建一个表名为user的表来存储用户数据:
四个字段分别为账户,密码,是否记住密码,以及注册时填写的邮箱。当然你会命令行更好了! 下面是连接我们的数据库:
#include#includeQSqlDatabase dbconn;QSqlQuery query;if(QSqlDatabase::contains(QSqlDatabase::defaultConnection)){ dbconn = QSqlDatabase::database(QSqlDatabase::defaultConnection);}else{ dbconn = QSqlDatabase::addDatabase(\"QMYSQL\");}dbconn.setHostName(\"127.0.0.1\");//主机名字dbconn.setDatabaseName(\"test\");//数据库名字dbconn.open(\"root\", \"xxxxxx\"); //第一个参数写用户名,这里我们就写root就可以,第二个参数密码是mysql的登陆密码。//可以使用如下语句判断是否连接成功if(dbconn.open(\"root\", \"xxxxxx\")){//如果判断为真,则连接成功}query = (QSqlQuery)dbconn; //进行绑定 此后可以使用query对象对数据库进行操作。 有很多人可能会提示数据库头文件的问题,如果你已经配置好了mysql,上翻开头的错误链接。
4.1.2 邮箱发送
邮箱发送的代码是我从网上抄下来的,原因是我还不太熟悉,大牛勿喷。 Qt5基于smtp服务发送电子邮件
想要通过代码登录我们的邮箱,需要开通stmp服务,登录我们的QQ邮箱,依次设置——账户——下拉开头stmp服务,这时它会出现一个授权码,这就是我们通过第三方登录的密码。
设置好以后上代码: 创建一个名为stmp的头文件:
#ifndef SMTP_H#define SMTP_H#include#include#includeclass Smtp{public: Smtp(QByteArray username,QByteArray password); ~Smtp(); void send(QByteArray recvaddr,QString subject,QString content);private: QTcpSocket * clientsocket; QByteArray username; QByteArray password; QByteArray recvaddr; QByteArray mailfrom = \"mail from:<\"; QByteArray rcptto = \"rcpt to:<\"; QByteArray prefrom = \"from:\"; QByteArray preto = \"to:\"; QByteArray presubject =\"subject:\"; QString subject; //主题 QString content; //发送内容 QByteArray recvdata; //接收到的数据};#endif // SMTP_H 创建一个名为stmp的C++文件:
#include \"smtp.h\"#includeSmtp::Smtp(QByteArray username,QByteArray password) //初始化发送者{ if(username.contains(\"@qq\")) { this->username = username; this->password = password; } else qDebug()<<\"NOT qq\";}void Smtp::send(QByteArray recvaddr,QString subject,QString content) //发送邮件{ this->recvaddr = recvaddr; this->subject = subject; this->content = content; QByteArray usernametmp = this->username; QByteArray recvaddrtmp = this->recvaddr; clientsocket=new QTcpSocket(); this->clientsocket->connectToHost(\"smtp.qq.com\",25,QTcpSocket::ReadWrite); this->clientsocket->waitForConnected(1000); this->clientsocket->waitForReadyRead(1000); recvdata = clientsocket->readAll(); qDebug()<clientsocket->write(\"HELO smtp.qq.com\r
\"); this->clientsocket->waitForReadyRead(1000); recvdata = clientsocket->readAll(); qDebug()<clientsocket->write(\"AUTH LOGIN\r
\"); this->clientsocket->waitForReadyRead(1000); recvdata = clientsocket->readAll(); qDebug()<clientsocket->write(username.toBase64().append(\"\r
\")); this->clientsocket->waitForReadyRead(1000); recvdata = clientsocket->readAll(); qDebug()<clientsocket->write(password.toBase64().append(\"\r
\")); this->clientsocket->waitForReadyRead(1000); recvdata = clientsocket->readAll(); qDebug()<clientsocket->write(mailfrom.append(usernametmp.append(\">\r
\"))); this->clientsocket->waitForReadyRead(1000); recvdata = clientsocket->readAll(); qDebug()<\r
\")); this->clientsocket->write(rcptto.append(recvaddrtmp.append(\">\r
\"))); this->clientsocket->waitForReadyRead(1000); recvdata = clientsocket->readAll(); qDebug()<\r
\")); //data表示开始传输数据 this->clientsocket->write(\"data\r
\"); this->clientsocket->waitForReadyRead(1000); recvdata = clientsocket->readAll(); qDebug()<username; recvaddrtmp = this->recvaddr; this->clientsocket->write(prefrom.append(usernametmp.append(\"\r
\"))); this->clientsocket->write(preto.append(recvaddrtmp.append(\"\r
\"))); this->clientsocket->write(presubject.append(subject.toLocal8Bit().append(\"\r
\"))); this->clientsocket->write(\"\r
\"); this->clientsocket->write(content.toLocal8Bit().append(\"\r
\")); this->clientsocket->write(\".\r
\"); this->clientsocket->waitForReadyRead(1000); recvdata = clientsocket->readAll(); qDebug()<clientsocket->write(\"quit\r
\"); this->clientsocket->waitForReadyRead(1000); recvdata = clientsocket->readAll(); qDebug()<clientsocket;} 原文作者是使用163邮箱,我这里使用qq邮箱,如使用163,只需要将代码中qq替换为163即可,下面是如何发送邮件:
//第一个参数是发送者邮箱,第二个授权码,并不是邮箱密码,要注意Smtp smtp(\"2506897252@qq.com\",\"XXXXXXXXXXXXX\"); //发送邮件smtp.send(\"接收者邮箱地址\",\"标题\",\"内容\");//稍后要发送的验证码只需要对字符串进行简单改动即可。4.2 登录主界面
4.2.1 界面背景及按钮效果
界面背景是我自己用ps画的,我们将图片资源统一放到一个名为lib的文件夹里,方便管理。 如何在qt添加资源文件呢?右键项目创建qt Resource File 这个就是资源文件,建好以后,添加我们做好的背景资源。
然后双击我们的ui文件,打开设计师界面,右键我们的窗体,打开改变样式表,添加资源,选择border-image,添加我们的刚才加载好资源文件,如果仅仅是这样的话,添加之后,你会发现不单单是界面,连界面上的一些控件都有了背景颜色,这个时候我就应该约束一下,让资源仅作用于界面:
border-image: url(:/new/prefix1/C:/Users/fdog/Desktop/lib/mainblack.jpg);//改为如下形式 只作用于MyDialog_2 #MyDialog_2{border-image: url(:/new/prefix1/C:/Users/fdog/Desktop/lib/mainblack.jpg);}不出意外的话的,现在显示正常了,别高兴的太早,如果你现在运行该窗体,可能会不显示背景,解决方法是,打开左栏的项目,如果Sha build 有打勾的话,去掉他,就可以显示背景了。
下面来说说鼠标悬浮按钮上的的效果
如果使用默认按钮的话,其实是有效果的,但一旦加入我们自己的资源,默认效果就没了,怎么做呢,在这个窗体的cpp文件构造函数中加入如下代码:
//这里的pushBuuton_2是按钮的名字, ui->pushButton_2->setStyleSheet(\"QPushButton{border-image: url(:/new/prefix1/C:/Users/fdog/Desktop/lib/blackButton_1.jpg);}\" \"QPushButton:hover{border-image:url(:/new/prefix1/C:/Users/fdog/Desktop/lib/blackButton_2_2.jpg);}\" \"QPushButton:checked{border-image:url(:/new/prefix1/C:/Users/fdog/Desktop/lib/blackButton_2_3.jpg);}\"); //代表这按钮的三种状态显示 ,分别是未选中, 悬浮,点击还想到一点就是按钮点击时有焦点框的,可以加入代码去除:
ui->pushButton_3->setStyleSheet(\"padding: -1\"); //不单单适用于按钮哦4.2.2 账户/密码校验
账户/密码校验思路就是将用户输入的账户和密码的文本框数据保存下来,与数据库做对比,如果正确,则登录成功,否则提示错误。
这里账户之所以不使用文本框而使用了下拉列表框,是为了显的更加真实。 这里有一个知识点,刚创建的下拉列表框是不具备输入的功能,在属性里面将editable打勾即可。
//这两行代码是限制输入的,写在构造函数 ui->comboBox->setValidator(new QRegExpValidator(QRegExp(\"[0-9]+#34;)));//只能输入数字 ui->lineEdit_2->setEchoMode(QLineEdit::Password);//以黑点显示 //遍历表user 连接数据库代码上面已说,这里不再列出,query已定义 query.exec(\"select * from user\"); QStringList mysqlMonth; //用于保存遍历到的账号,这个类型类似于数组和集合while(query.next()) { //将所有账户进行保存 mysqlMonth<comboBox->addItems(mysqlMonth); //将遍历的账号写入下拉列表框 dbconn.close();//断开连接 4.2.3 记住密码实现
实现思路是登录的时候判断复选框是否被勾选,二次登陆时遍历数据库的tf字段,如果是\"1\"则显示密码。\"0\"则不显示密码,这样就起到了记住密码的功能。
//提取的账户和密码 username = ui->comboBox->lineEdit()->text(); userpassword = ui->lineEdit_2->text();//查询数据库是否有匹配账户QString S =QString(\"select * from user where username="%1" and userpassworld="%2" \").arg(username).arg(userpassword);if(query.exec(S)&&query.next()) //网上很多教程只用了query.exec(S),这样是否匹配到都会返回真是无法达到预期效果的{ if(ui->checkBox->isChecked()) //判断复选框是否被勾选,如果勾选,数据库标标记记住密码 { //更新数据库将字段为username的那一行,修改tf为\"1\"代表记住密码 S = QString(\"update user set tf = "%1" where username = "%2"\").arg(\"1\").arg(username); query.exec(S); }else {//否则 tf写入\"0\"代表不记住密码 S = QString(\"update user set tf = "%1" where username = "%2"\").arg(\"0\").arg(username); query.exec(S); }}//启动软件加载账户以及密码//在构造函数加入槽函数QObject::connect(ui->comboBox,SIGNAL(currentIndexChanged(QString)),this,SLOT(printfText()));//通过槽 将账号与密码进行关联//该函数加载账户和密码void MyDialog::printfText(){//遍历账户 query.exec(\"select * from user\"); //保存账号 假定最多5个账户 QString account_qstr[5]; //保存账户是否记录密码 QString remember_qstr[5]; //用于数组 int i = 0; int j = 0; while(query.next()) { //保存遍历值 account_qstr[i++] = query.value(1).toString();//第二个字段 userpassworld remember_qstr[j++] = query.value(2).toString();//第三个字段 tf } //ui->comboBox->currentIndex()==0代表下拉列表框第一个选项 再判断tf是否为\"1\" 如果条件成立,则显示密码 if(ui->comboBox->currentIndex()==0 && remember_qstr[0]==\"1\") { ui->lineEdit_2->setText(account_qstr[0]); } if(ui->comboBox->currentIndex()==1 && remember_qstr[1]==\"1\") { ui->lineEdit_2->setText(account_qstr[1]); } if(ui->comboBox->currentIndex()==2 && remember_qstr[2]==\"1\") { ui->lineEdit_2->setText(account_qstr[2]); } if(ui->comboBox->currentIndex()==3 && remember_qstr[3]==\"1\") { ui->lineEdit_2->setText(account_qstr[3]); } if(ui->comboBox->currentIndex()==4 && remember_qstr[4]==\"1\") { ui->lineEdit_2->setText(account_qstr[4]); }}4.2.4 登录/注册/忘记密码按钮响应
思路就是创建槽函数,来发出信号,隐藏主界面,来显示次界面。
//就拿登录来说//主窗口头文件#ifndef MYDIALOG_H#define MYDIALOG_H#include namespace Ui {class MyDialog;}class MyDialog : public QDialog{ Q_OBJECTpublic: explicit MyDialog(QWidget *parent = 0); ~MyDialog();signals: void showmainwindow();//显示主窗口信号private: Ui::MyDialog *ui;};#endif // MYDIALOG_H//然后在主窗口cpp写void MyDialog::on_pushButton_clicked()//登录按钮被触发{this->hide();//隐藏主界面 emit showmainwindow();//发出显示登录对话框}//绑定槽函数显示登录对话框//d是主界面对象 w是登录对话框对象,如果showmainwindow()发出信号,w的成员函数receivelogin()会被执行QObject::connect(&d,SIGNAL(showmainwindow()),&w,SLOT(receivelogin()));//然后在登录对话框cpp中编写receivelogin()函数void MainWindow::receivelogin(){ this->show();//显示登录对话框} 4.3 注册账户界面
4.3.1 发送验证码
void MyDialog_2::on_pushButton_clicked() //发送验证码{ //邮箱地址 QString mailaddress_qstr = ui->lineEdit_3->text(); //获取用户输入的邮箱地址 std::string mailaddress_str = mailaddress_qstr.toStdString(); const char * mailaddress_c = mailaddress_str.c_str(); //这里因为抄下来的代码是char * 类型的,所以我们需要转换一下 //随机生成验证码 qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); verificationcode = qrand()%(99999 - 10000) + 10000;//产生一个5位数的随机数 //将验证码加入字符串 QString verificationcode_qstr = QString(\"验证码为%1,若非本人操作,请勿告诉他人。——————信息来自花狗科技\").arg(verificationcode); std::string verificationcode_str = verificationcode_qstr.toStdString(); const char * verificationcode_c = verificationcode_str.c_str(); //登录邮箱 Smtp smtp(\"2506897252@qq.com\",\"XXXXXXXXX\"); //第一个参数是发送者邮箱,第二个授权码,并不是邮箱密码 //发送邮件 smtp.send(mailaddress_c,\"验证信息\",verificationcode_c);}4.3.2 验证码验证
void MyDialog_2::on_pushButton_2_clicked() //注册(成功则写入数据库){ QString register_qstr = ui->lineEdit_4->text();//获取用户输入的验证码 //将字符串转为整形进行验证码判断 int verificationcode_2 = register_qstr.toInt(); if(verificationcode_2 == verificationcode) { QMessageBox::about(this,\"About\",QString::fromUtf8(\"注册成功\")); QString username = ui->lineEdit->text();//获取账户 QString userpassword = ui->lineEdit_2->text();//获取密码 QString mail = ui->lineEdit_3->text();//获取注册邮箱,用作找回密码时的凭证 QString str = QString(\"INSERT INTO user (username,userpassworld,tf,mail) VALUES ("%1","%2","%3","%4")\").arg(username,userpassword,\"0\",mail); query.exec(str); dbconn.close(); } else { QMessageBox::about(this,\"About\",QString::fromUtf8(\"验证码错误\")); }}4.3.3显示倒计时
大家也应该知道发送验证码之后会有一个时间显示,为了逼真,我们也来做一个
#include\"QTimer\"#include\"QTime\"QTimer * timer;int count = 60; //倒计时connect(timer,SIGNAL(timeout()),this,SLOT(myslot())); //绑定槽函数void MyDialog_2::on_pushButton_clicked() //发送验证码{//这行代码也是写在上一个函数中的,只不过我拆下来方便理解 //间隔1秒触发myslot() 来显示剩余秒数 timer->start(1000);}void MyDialog_2::myslot() //显示倒计时{ QString count_qstr = QString(\"剩余%1秒\").arg(count--); ui->label_5->setText(count_qstr);//将剩余秒数写在标签上 if(count == -1) { //如果用户没有返回登陆,倒计时结束应停止计时 timer->stop(); }}4.4 忘记代码界面
忘记代码其实和注册代码差不多,只是这次的邮箱需要我们从数据库获取
oid MyDialog_3::on_pushButton_clicked() //发送验证码{ QString username = ui->lineEdit->text();//获取账户 QString S =QString(\"select * from user where username="%1" \").arg(username); if(query.exec(S)&&query.next()) { //有该账户,则查询该账户注册时的邮箱地址 QString mailaddress_qstr = query.value(3).toString(); //这里的地址需要通过数据库记录的邮箱地址来确定 std::string mailaddress_str = mailaddress_qstr.toStdString(); const char * mailaddress_c = mailaddress_str.c_str(); //随机生成验证码 qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); verificationcode_2 = qrand()%(99999 - 10000) + 10000; //将验证码加入字符串 QString verificationcode_qstr = QString(\"验证码为%1,若非本人操作,请勿告诉他人。——————信息来自花狗科技\").arg(verificationcode_2); std::string verificationcode_str = verificationcode_qstr.toStdString(); const char * verificationcode_c = verificationcode_str.c_str(); //登录邮箱 Smtp smtp(\"2506897252@qq.com\",\"XXXXXXX\"); //第一个参数是发送者邮箱,第二个授权码,并不是邮箱密码 //发送邮件 smtp.send(mailaddress_c,\"验证信息\",verificationcode_c); } else { QMessageBox::about(this,\"About\",QString::fromLocal8Bit(\"
该账户未注册!\")); }}好了,登录界面就这些啦,我们下期再见!
【领 QT开发教程 学习资料, 点击下方链接莬费领取↓↓ ,先码住不迷路~】
点击这里:
关键词:
