Qt实战笔记-从零开始搭建一套库存管理系统-(四)数据库的连接、读写

那上一章节我们已经把最基本的UI框架搭建好了,这一章节我们尝试连接数据库,实现一些最基本的和数据相关的功能,比如注册和登录。

1、连接数据库

Qt中的Qt SQL模块提供了对数据库的支持,在使用Qt SQL模块中的这些类之前,需要在项目文件(.pro文件)中添加QT += sql这一行代码。

Qt支持的数据库类型有很多,我们这里选择了SQLite数据库,这是一个很轻量级的文本型数据库,Qt对它提供了很好的支持,当然也可以选择其他的数据库,比如MYSQL,SQL Server等。

考虑到复杂度,我们暂时将数据库部署到本地,后续可以探索通过网络访问数据库服务器的方式。

我们还是新建一个类,文件->新建文件或项目->文件和类->C++->C++ Class,类名称我这里设置为mySqlite,基本类为自定义。

sql呢最开始肯定得要先被初始化,在头文件mysqlite.h中,我们在mySqlite这个类中添加一个public函数 bool initSql(),用来初始化数据库,记得添加头文件QSqlDatabase,内容如下:

#ifndef MYSQLITE_H
#define MYSQLITE_H

#include <QSqlDatabase>

class mySqlite
{
public:
    mySqlite();
    bool initSql();
};
#endif // MYSQLITE_H

在mysqlite.cpp中,我们把initSql()函数体的内容补充完整;

bool mySqlite::initSql()
{
    QSqlDatabase myDB = QSqlDatabase::addDatabase("QSQLITE");
    myDB.setDatabaseName(QApplication::applicationDirPath() + "/Database/"+"myWMS.db");
    if(!myDB.open())
    {
        return false;
    }
    return true;
}

sql初始化实际上需要干两件事,一是先创建一个SQLite数据库连接,二是需要创建数据表。

我们现在已经创建了一个SQLiteL连接,db文件我们命名为myWMS.db,目录为Database,注意需要提前在可执行程序的目录内建立好Database这个文件夹,不然会连接失败。

接下来,我们在mainwindow中新建一个mySqlite实例,并调用它的initSql函数。

我们在mainwindow.h中增加一个成员mySqlite *mysql,在mainwindow的构造函数中,增加如下内容:

mysql = new mySqlite;
    if(mysql->initSql())
        qDebug()<<"连接成功";
    else
        qDebug()<<"连接失败";

这里我们用了qDebug函数来打印输出结果,方便调试,使用之前记得加上头文件#include <QDebug>。

运行之后,我们会在Qt Creator的输出面板中看到,显示连接成功,证明我们的数据库已经连接上了,我们打开项目的debug目录,也可以看到目录中增加了一个数据库文件。

2、建立数据表格

刚才已经说过了,数据库的初始化需要连接数据库,建立表格,数据连上了,接下来就得建立咱们需要的数据表了,因为我们的数据库就是不同的数据表构成的。

回到咱们的项目上,咱们的这个业务数据包含了用户数据,供应商数据,商品数据等等,这些不同的数据就需要用不同格式的数据表格来记录。

我们首先先准备用户表,数据表用来记录用户信息,用户在注册的时候,需要将用户的信息保存,并且在用户登录的时候,也要去数据库里查询,用户名和密码匹配才能登录成功。

我们先建立一个最简单的表结构,如下

用户ID 用户名称 密码 角色

用户ID是主键,用来区分用户的唯一性标识,类型为整型数字;

用户名称、密码和角色是字符型,长度暂定30。

下面我们通过代码在已经连接的数据库内建立这个表。

在mysqlite.h的类中,我们声明一个void createTable()函数和一个QSqlQuery *query;,在mysqlite.cpp中,函数体实现如下,query执行了一条创建表格的sql语句,记得加头文件#include <QSqlQuery>:

bool mySqlite::createTable()
{
    query=new QSqlQuery;
    QString str = "create table if not exists user("
                  "[id] integer primary key autoincrement,"
                  "[name] varchar(30),"
                  "[password] varchar(30),"
                  "[role] varchar(30)"
                  ")";
    if(!query->exec(str))
        return false;
    return true;
}

我们再把initSql()函数修改一下,如果数据库连接成功,就执行creatTable函数。

bool mySqlite::initSql()
{
    QSqlDatabase myDB = QSqlDatabase::addDatabase("QSQLITE");
    myDB.setDatabaseName(QApplication::applicationDirPath() + "/Database/"+"myWMS.db");
    if(!myDB.open())
    {
        qDebug()<<"db not open";
        return false;
    }
    else
    {
        if(!createTable())
            return false;
    }
    return true;
}

执行之后,数据库中的用户表就建好了,数据库文件可以用一些可视化管理软件查看和编辑,我这里用的是Sqliteman这款软件,打开咱们刚才在Database中生成的db文件,可以看到已经建立好user这个表格了。

表格已经建立好,接下来我们现在就可以往这个表格写数据了,下面就通过注册这个过程来写测试一下吧。

3、写入数据

从这里开始,我们要接触到Qt的信号与槽的机制了,简单来说,就是信号被触发后,与信号连接的槽函数就会执行,信号有很多种,比如我们在登录界面添加的两个按钮,如果按钮被点击,就会发射点击的信号。我们先在mainwindow类中添加一个槽函数,用来在用户点击注册按钮之后执行,函数名就叫userRegister吧。

函数体内容如下:

void MainWindow::userRegister()
{
    QString name = myLoginDialog->nameEdit->text();
    QString password = myLoginDialog->passwordEdit->text();
    QString role = "staff";
    if(!mysql->registerUser(name,password,role))
        qDebug()<<"failed";
    else
        qDebug()<<"successful";
}

在这里我们把登录界面的两个输入框(用户名、密码)的内容获取到了,并把角色的参数写死为员工(staff),然后调用了mysql的registerUser函数。把用户名、密码、角色参数一并传过去了,获取一个bool的返回值。

接下来我们看看mysql的registerUser是怎么实现的,这个函数的主要功能就是将用户名、密码、角色信息保存在数据库中。

bool mySqlite::registerUser(QString name,QString password,QString role)
{
    query=new QSqlQuery;
    QString str = QString("insert into user values(null,'%1','%2','%3')").arg(name).arg(password).arg(role);
    if(!query->exec(str))
        return false;
    return true;
}

这里我们在建表的时候已经把user表的第一列id定义为了自增长的整数,所以我们这里如果传的值为null,数据库会将id这个主键自增长的添加数据。

接下来我们回到mainwindow.cpp中,将登录页的注册按钮的点击信号与userRegister这个槽函数连接起来,我们在creatTool函数中添加相应语句,如下:


 connect(myLoginDialog->registButton,&QPushButton::clicked,this,&MainWindow::userRegister);

执行之后,点击登录按钮,在弹出的登录框中输入用户名和密码,然后点击“注册”按钮。

使用Sqliteman打开数据库文件,查看内容,点击user数据表,可以发现我们的注册信息已经被保存到数据库中了。

4、读取数据

对于数据库的操作无法就是增删改查,我们在上一小节里面已经实现了增加数据,这个小节我们来实现查询,通过实现“用户登录”这个功能,可以完整的体验查询数据的过程。

和注册的过程一样,我们首先在mainwindow中增加一个槽函数,来接收“登录”按钮点击后触发的信号,就命名为userLogin(),函数体实现如下:

void MainWindow::userLogin()
{
    QString name = myLoginDialog->nameEdit->text();
    QString password = myLoginDialog->passwordEdit->text();
    mysql = new mySqlite;
    if(!mysql->loginUser(name,password))
        qDebug()<<"failed";
    else
        qDebug()<<"successful";
}

接下来我们去mySqlite类中声明一个函数:bool loginUser(QString name,QString password);

函数实现如下:

bool mySqlite::loginUser(QString name,QString password)
{
    query=new QSqlQuery;
    QString str=QString("select * from user where name= '%1' and password = '%2' ").arg(name).arg(password);
    query->exec(str);
    return query->next();
}

我们使用sql的select语句进行查询,将查询的结果通过QSqlQuery的next进行访问,如果查询结果为空,则next指向的结果返回为false,即证明这个用户名和密码在数据库中没有匹配项。

在mainwindow的creatTool()中增加一条语句,将登录按钮的触发信号和槽函数连接在一起:

connect(myLoginDialog->loginButton,&QPushButton::clicked,this,&MainWindow::userLogin);

运行程序,在登录窗口输入用户名和密码,如果输入上一步已经注册号的用户名和密码,可以看到程序输出为成功,如果使用其他的信息登录,则显示失败,证明咱们已经通过数据库的读取初步实现了登录功能。

5、逻辑优化

到这里,其实我们已经实现了与数据库有关的最基本功能,即连接数据库、建立数据表、写入数据、读取数据等功能,但是,作为一个实际使用的软件的话, 还有很多逻辑不清晰的地方,比如,如果数据库文件找不到了怎么办?每次启动程序都需要初始化数据库吗?点击注册和登录按钮之后,后续的动作是什么?也没有窗口的变化与提示。那接下来,我们把整个注册登录的逻辑再优化一下。

关于数据库的初始化,我们在第一小节已经知道,需要两个步骤,一个是连接数据库,一个是建立数据表。但这有一个前提,就是如果数据库已经初始化过,我们就没有必要在进行初始化了,怎么判断数据库是否需要初始化呢?我们这里可以就依是否存在数据库文件为标准,如果检测到数据库文件,我们就认为数据库是已经初始化过,不需要再进行初始化了,只需要连接数据库就可以了。

整个前期的准备工作流程如下:

可以看到,连接数据库和建立数据表这两个功能我们可以通过两个函数来实现,然后把这两个函数放到初始化的函数当中,这样,函数的调动就更加的灵活了。

我们在mySqlite中新建一个bool connectDB()函数,函数体内容如下:

bool mySqlite::connectDB()
{
    QSqlDatabase myDB = QSqlDatabase::addDatabase("QSQLITE");
    myDB.setDatabaseName(QApplication::applicationDirPath() + "/Database/"+"myWMS.db");
    if(!myDB.open())
        return false;
    return true;
}

然后,initSql函数就可以改为如下:

bool mySqlite::initSql()
{
    if(!connectDB())
        return false;
    else if (!createTable())
    {
        return false;
    }
    return true;
}

在mainwindow中增加一个void checkDB函数,在构造函数中调用,用来检测数据库的状态,实现上面流程图所示的逻辑判断,即如果存在数据库文件,证明不需要初始化,只连接数据库就可以了,如果不存在数据库文件,则证明需要初始化,完成连接数据库和建立数据表两个流程。

void MainWindow::checkDB()
{
    QString dbFilePath = QApplication::applicationDirPath() + "/Database/"+"myWMS.db";
    QFile file(dbFilePath);
    if(!file.exists())
    {
        QMessageBox messageWarning(QMessageBox::Warning,"警告","数据库配置失败,是否初始化数据库",QMessageBox::Yes|QMessageBox::No);
        if (messageWarning.exec()==QMessageBox::Yes)
        {
            mysql = new mySqlite;
            if(mysql->initSql())
                QMessageBox::information(this, "数据库信息", "数据库已重置。");
            else
                QMessageBox::information(this, "数据库信息", "数据库重置失败,请联系系统管理员。");
        }
    }
    else
    {
        mysql = new mySqlite;
        if(!mysql->connectDB())
            QMessageBox::information(this, "数据库信息", "数据库连接失败,请联系系统管理员。");
        else
            qDebug()<<"连接成功";
    }
}

这里使用QFile文件类,来调用其exists()函数来判断数据库文件是否存在,如果不存在,则通过弹窗提示用户,并让用户决定是否需要进行初始化,如果选择是,则调用mySqlite的initSql()进行初始化。如果数据库文件存在,则直接调用mySqlite的connectDB()连接数据库,如果连接失败,弹窗提示用户。

这里也引用了Qt的弹窗类QMessageBox,可以实现诸如警告,信息,关于,询问等窗口,具体使用说明可以参考Qt的帮助文档。

我们先删除Database目录下的数据库文件,编译运行,可以发现,程序弹窗给我们提示,我们选择“是”,进行初始化。

当我们点击注册按钮的时候,如果用户注册成功或者失败,我们需要给用户以相应的提示。

我们把mainwindow中的userRegister()和userLogin()修改如下:

void MainWindow::userRegister()
{
    QString name = myLoginDialog->nameEdit->text();
    QString password = myLoginDialog->passwordEdit->text();
    QString role = "staff";
    mysql = new mySqlite;
    if(!mysql->registerUser(name,password,role))
        QMessageBox::information(this, tr("消息"), tr("注册失败,请重试!"), QMessageBox::Ok);
    else
    {
        QMessageBox::information(this, tr("消息"), tr("注册成功!"), QMessageBox::Ok);
        userLogin();
    }
}
void MainWindow::userLogin()
{
    QString name = myLoginDialog->nameEdit->text();
    QString password = myLoginDialog->passwordEdit->text();
    mysql = new mySqlite;
    if(!mysql->loginUser(name,password))
        QMessageBox::information(this, tr("消息"), tr("登录失败,请重试!"), QMessageBox::Ok);
    else
    {
        QMessageBox::information(this, tr("消息"), tr("登录成功!"), QMessageBox::Ok);
        myLoginDialog->hide();
        loginAct->setVisible(false);
        userInfoLabel->setText("已登录:"+name);
        userInfoLabel->show();
    }
}

即注册成功之后,给用户以弹窗提示,就立刻将注册信息传给登录函数进行登录,登录结果以弹窗通知给用户。同时,将登录窗口隐藏不显示,登录按钮也要隐藏,所以这里需要将将loginAct这个动作变量修改为mainwindow的成员变量。

另外,我又在toolBar中增加了一个标签,用来显示用户登录状态信息,其默认状态是隐藏的,登录成功后会显示。

creatTool()增加了如下内容,当然,userInfoLabe也l需要先在头文件中声明;

    userInfoLabel = new QLabel("");
    loginToolBar->addWidget(userInfoLabel);
    userInfoLabel->hide();

以上调整完之后,整个登录和注册功能就基本上符合使用需求了。

好了,这个章节我们就通过使用用户注册和登录的功能来完成了Qt和数据库的第一次接触,后面我们随着功能的深入会继续增加更多和数据库的交互。

发布了8 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/hello_monster/article/details/98181526