当前位置:网站首页>Fdog series (V): use QT to imitate QQ to realize login interface to main interface, function chapter.
Fdog series (V): use QT to imitate QQ to realize login interface to main interface, function chapter.
2022-07-06 16:52:00 【Flower dog fdog】
List of articles
One . Preface
Fdog The series has been catalogued :
Fdog series ( Four ): Use Qt Frame imitation QQ Realize the login interface , Interface .
Fdog series ( 5、 ... and ): Use Qt imitation QQ Realize the login interface to the main interface , Function section . Current chapter
After reading this article , You will learn to :
How to save login data
Implement whether to remember the password
How to get local data
The drop-down box appears in the login interface
Delete an account from the drop-down list box
Change the options , real-time display
The customization of drop-down box is more complex , I saw some netizens ask how to realize it in the comments area , Don't worry. , Here it comes ! Look at the end of this article , You will learn him .
Meanwhile, the complete project code has been uploaded github:Fdog Instant messaging software Seeking stars !
Two . Text
1. How to save the first login data
Let's analyze first :
Data to save ,1. Head portrait 2. account number 3. password 4. Remember password or not , And the third password depends on whether the fourth user checks remember password .
How to save data , Here are two ways :1. Using text save ,2. Use ini Profile saving . Both methods are OK . For convenience , Here we use text saving , If you want to use ini preservation , You can refer to this one :QT Reading of learning notes INI file
Where documents are stored , It's unwise to use absolute paths here , Relative address should be used , The idea is to get the directory of the executable file , Then create a user file in its directory .
User file structure : establish FdogUserFile Folder , Then create a folder named user account , This folder includes picture files and a text file , Picture files are avatars , It's also named after the user's account , The text file is named data, The account number and password are stored in it , Here's a format , The first line is the account number , The second line is the code , When the second line is empty , It means that the user did not choose to remember the password .
It should be noted that files should not be created repeatedly here , There should be a judgment , Judge whether the current user information file is created , Created if it does not exist , If it exists, it can be updated .
I almost forgot about our database , Before all this , Users and passwords should be compared to database data , If the match , Just download the avatar from the server and execute the above content .
Here's the code to implement this idea , Now suppose the photo already exists on the server , For example, when you enter a web address :https://www.fdogcsdn.cn/img/10001.jpg
The page will display a picture .
As for how to make web pages display pictures , I'll write below , Now we just need to consider how to use the code to download pictures and compare with the database content .
Create a database class :usersql
#include<QNetworkAccessManager>
#include<QNetworkReply>
#include<QPixmap>
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
// The top three lines prevent Chinese garbled
class Usersql
{
private:
QSqlDatabase dbconn;// Connect to database
QSqlQuery query; // Query operation
QString account; // account number
QString passwd; // password
QString iconurl; // Address
QPixmap icon; // Head portrait
public:
void conndata(); // Connect to database
bool queryuser(QString user,QString password); // Check whether there is such an account
QPixmap geticonurl(QString url);// Download pictures from the Internet according to the address
QPixmap getPixmapIcon(QString url);//url Account number , Get your avatar address through your account
};
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");// Host name It's also a server ip If you use a local database test , Then use 127.0.0.1
this-> dbconn.setDatabaseName("fdogsql");// Database name
if(this->dbconn.open("root", "111111")) // user name password
{
// If the judgment is true , The connection is successful
//qDebug()<<"success";
}
this->query = (QSqlQuery)this->dbconn; // Binding After that, you can use query Object to operate on the database .
}
bool Usersql::queryuser(QString user, QString password)
{
this->query.exec("select * from user");
while(query.next())
{
// Traverse account value The value in represents the field ,0 It's the first one ,1 That's the second one
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()<<" The account exists ";
return true;
}
else
{
qDebug()<<" The account does not exist ";
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));
// After the request ends and the download is complete , Exit the sub event loop
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
// Turn on the sub event loop
loop.exec();
QByteArray jpegData = reply->readAll();
this->icon.loadFromData(jpegData);
return icon;
}
QPixmap Usersql::getPixmapIcon(QString url)
{
QString strurl;
// The database queries the account
this->query.exec("select * from user");
while(query.next())
{
// Traverse account
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;
}
Then take a look at the code executed when you click the login button
void Login::on_pushButton_clicked()
{
//ui->lineEdit_2 It's the account text box ui->lineEdit It's the password text box
sqconn.conndata();// Connect to database
bool isuser = sqconn.queryuser(ui->lineEdit_2->text(),ui->lineEdit->text());// Input content query
// Judge whether the user exists
if(isuser)
{
// Just get the account number
QString account = ui->lineEdit_2->text(); // Account
this->sqconn.queryUserInfo(account);// Get a nickname from your account , password ( If the user chooses to remember the password , Then save the password ), Head portrait
QString name = sqconn.getName();
QString passwd="";
if(ui->checkBox_2->isChecked())// Judge whether the user saves the password
{
passwd = sqconn.getPasswd();
}
QPixmap icon = sqconn.getIcon();
// Get the current running directory of the program
QString fileName = QCoreApplication::applicationDirPath();
// User directory
QString add = "//..//FdogUserFile";
// Create user folder
fileName = fileName + add +QString("//%1").arg(account);
// Information preservation
QDir * file = new QDir;
// Does the folder exist , If it exists, it means that the information already exists , Just update the content .
bool exist_1 = file->exists(fileName);
if(exist_1)
{
//qDebug()<<" establish ";
QFile file(fileName +"//data.txt");
qDebug()<<fileName +"//data.txt";
if(file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate))
{
//qDebug()<<"txt File created successfully ";
}
QTextStream stream(&file);
// write in
if(passwd=="")stream<<name;
else stream<<name<<"\n"<<passwd;
//qDebug()<<"tup:"<<account;
icon.save(fileName+QString("//%1.jpg").arg(account),"JPG");
file.close();
}
else
{
// Create... If it doesn't exist
bool ok = file->mkpath(fileName);
if(ok)
{
//qDebug()<<" establish ";
QFile file(fileName +"//data.txt");
qDebug()<<fileName +"//data.txt";
if(file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate))
{
//qDebug()<<"txt File created successfully ";
}
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()<<" Not created successfully ";
}
}
this->hide();// Hide login window
systemtrayicon->hide();// Hide the system tray
// Initialize the main interface w Is the main interface class defined in the header file , It's just a demonstration .
w = new MainWindow(account);
// Display main interface
w->show();
// Display the system tray icon
w->showicon();
}
else
{
// The user does not exist
}
}
When you log in to your account , Create effects :
Of course, it's not safe to save passwords in clear text , You can refer to an encryption article I wrote before : Asymmetric encryption algorithm ——RSA Algorithm principle and C++ Realization
Then, how to make the server display the photos correctly , Create a fdogpoject/fdog/img The path of , stay img Our photos are stored in the folder , This, of course, , We can't get through https://www.fdogcsdn.cn/img/10001.jpg To show the picture , There's still something to change .
I use it. tomcat Built Services , So in conf Change under folder server.xml file , add to :
<Context reloadable="true" docBase="/fdogpoject/fdog/img/" path="/img"/>
And then restart tomcat Then you can access it .
2. How to get the account information that has been logged in , And finish customizing the following boxes
This step is much simpler than how to save information , Just display your avatar and file contents in the drop-down list box .
Login interface class :
class Login : public QWidget
{
private:
QVector<int> infoListsign;
QSignalMapper * myMapper;
QStringList infoList; // The user account
QStringList infopasswd; // User password
QStringList icon; // The address where the picture is kept
public:
explicit Login(QWidget *parent = 0);// Constructors
QStringList GetDirNameList(const QString &strDirpath);// It is used to obtain all accounts under the user file ( It's actually getting all the file names in the directory )
};
Login::Login(QWidget *parent) :
QWidget(parent),
ui(new Ui::Login)
{
ui->setupUi(this);
// obtain exe Running directory
QString fileName1 = QCoreApplication::applicationDirPath()+"//..//FdogUserFile";
// Get directory
infoList = GetDirNameList(fileName1);
// Load custom drop-down list box
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++)
{
// Get the account number
QString local_account = infoList.at(i);
// Get a nickname
QString local_name;
// Get password
QString local_passwd;
// Get a picture
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()<<" File opening failure "<<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)
{
// You should also check to see if there is a password , If so, read , And show the tick
infopasswd.insert(i,str);
//qDebug()<<" Password "<<str;
local_passwd.append(str);
this->ispasswd =false;
}
else
{
local_name.append(str);
this->ispasswd =true;
}
qDebug()<<infopasswd;
}
QHBoxLayout *horLayout = new QHBoxLayout();// Horizontal layout
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)
{
QDir dir(strDirpath);
QFileInfoList Info_list = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
QListIterator<QFileInfo> Iterator(Info_list);
QStringList strDirNameList;
QFileInfo Info;
while (Iterator.hasNext())
{
Info = Iterator.next();
if (Info.isDir())
{
strDirNameList << QDir(Info.absoluteFilePath()).dirName();
}
}
return strDirNameList;
}
The point of customizing the drop-down list box is these :
QListWidget * m_AccountList; // Custom drop down list box
// Load custom drop-down list box
m_AccountList = new QListWidget(this);
m_AccountList->setFocusPolicy(Qt::NoFocus);
ui->comboBox->setModel(m_AccountList->model());
ui->comboBox->setView(m_AccountList);
// Execute the following code once for each account
QHBoxLayout *horLayout = new QHBoxLayout();// Horizontal layout
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->setIcon(QIcon(":/lib/delete.png"));
b1->setFixedSize(32,32);
b1->setStyleSheet("background:rgba(200,200,200,0);border-style:solid;");
horLayout->addWidget(la); // The head in front
horLayout->addWidget(la2);// Middle name
horLayout->addWidget(b1);// Delete button at the back
QWidget *widget =new QWidget(this);
widget->setLayout(horLayout);
QListWidgetItem * Listitem = new QListWidgetItem(m_AccountList);
m_AccountList->setItemWidget(Listitem,widget);
3. Delete an account from the drop-down list box
Bind a signal slot for each delete button
void Login::deleteaccount(int i) // What's coming in is the marked numbers
{
//QMessageBox::information(NULL, " Tips ", " Do you want to delete this account information ",QMessageBox::Yes|QMessageBox::No);
QMessageBox *message = new QMessageBox(QMessageBox::Question,tr(" Tips "), tr(" Do you want to delete the account information "), QMessageBox::Yes | QMessageBox::No,this);
int result = message->exec();
//infoListsign 0 1 2 3 0 1 2 3 0 1 2 1 2 3
// Here is a point to be aware of , The number that marked each button would not change , But when we delete one from the list item after , The rest of the list item It will sort automatically
// Therefore, it is impossible to simply delete the original marked number , We can use a vector, Store the marked number in , The value being deleted is the subscript of the tag number
// If we only depend on the number of marks , For example, I want to delete the first line , Namely 0, At this time, its subscript is also 0, There's no problem with that , But the second time it goes wrong , I want to delete the second line , When I click delete
// In fact, the returned value should be 1, But after the list is automatically sorted , The original 1 Turned into 0, The original 2 Changed 1.
switch(result)
{
case QMessageBox::Yes:
infoList.removeAt(infoListsign.indexOf(i));
infopasswd.removeAt(infoListsign.indexOf(i));
icon.removeAt(infoListsign.indexOf(i));
// Whether the current index is a delete object , if , Use the first
if(infoListsign.indexOf(i)==ui->comboBox->currentIndex())
{
if(infoList.length()!=0)
{
ui->comboBox->setCurrentIndex(0);
}
}
if(infoList.length()==0)
{
ui->lineEdit_2->setText("");
ui->lineEdit->setText("");
ui->label_4->setStyleSheet("border-image: url(:/lib/fdogicon.png);border-width:0px;border-style:solid;border-color: rgb(255, 255, 255);border-radius:33px;");
this->m_AccountList->setItemHidden(this->m_AccountList->item(0),true);
return;
}
// Hide account information this->m_AccountList->setItemHidden(this->m_AccountList->item(i),true);
// Delete account information
QListWidgetItem * item;
qDebug()<<" error 0";
qDebug()<<"infoListsign.indexOf(i)"<<infoListsign.indexOf(i);
item = this->m_AccountList->takeItem(infoListsign.indexOf(i));
qDebug()<<" error 1";
this->m_AccountList->removeItemWidget(item);
qDebug()<<" error 2";
delete item;
infoListsign.erase(infoListsign.begin()+infoListsign.indexOf(i));
break;
case QMessageBox::No:
// Do nothing
break;
}
}
4. The text box shows the correct content
It was said in the last article that , The account text box in the figure is actually composed of a text box and a drop-down list box , How to modify the content displayed in the login interface while changing the following list box ?
Right click combox, Go to slot , add to currentIndexChanged, The code is as follows
void Login::on_comboBox_currentIndexChanged(int index)
{
ui->checkBox_2->setChecked(false);
ui->lineEdit->setText("");
ui->lineEdit_2->setText(infoList.at(index));
if(infopasswd.at(index)!="")
{
ui->lineEdit->setText(infopasswd.at(index));
ui->checkBox_2->setChecked(true);
}
QString icon1 = icon.at(index);
ui->label_4->setStyleSheet(QString("border-image: url(%1);border-width:0px;border-style:solid;border-color: rgb(255, 255, 255);border-radius:33px;").arg(icon1));
// Start thinking about whether the user chooses to remember the password
}
If you don't understand QSignalMapper Class usage can refer to this article :QT Multiple button signals are bound to a slot function , Execute different business logic .
边栏推荐
- ~84 form supplement
- CMake速成
- Chapter 5 detailed explanation of consumer groups
- LeetCode 1020. Number of enclaves
- Shell_ 01_ data processing
- Full record of ByteDance technology newcomer training: a guide to the new growth of school recruitment
- @RequestMapping、@GetMapping
- LeetCode 1640. Can I connect to form an array
- ~76 sprite map
- Cmake Express
猜你喜欢
随机推荐
7-8 likes (need to continue to improve)
ByteDance new programmer's growth secret: those glittering treasures mentors
JS encapsulates the method of array inversion -- Feng Hao's blog
~83 form introduction
Submit several problem records of spark application (sparklauncher with cluster deploy mode)
~79 Movie card exercise
LeetCode1556. Thousand separated number
Jedis
Cmake error: could not create named generator visual studio 16 2019 solution
7-6 sum of combinatorial numbers
100张图训练1小时,照片风格随意变,文末有Demo试玩|SIGGRAPH 2021
Chapter 7__ consumer_ offsets topic
The concept of spark independent cluster worker and executor
~70 row high
LeetCode 1558. Get the minimum number of function calls of the target array
LeetCode 1552. Magnetic force between two balls
Solve the single thread scheduling problem of intel12 generation core CPU (II)
字节跳动2022校招研发提前批宣讲会,同学们最关心的10个问题
[unsolved] 7-15 shout mountain
Research Report on market supply and demand and strategy of China's four flat leadless (QFN) packaging industry