Qt+MySQL实现数据库图书管理系统
实验 5 数据库程序设计
一、实验目的
1、 设计并实现一个精简的图书管理系统,具有入库、查询、借书、还书、借书证管理等基本功能。
2、 通过本次设计来加深对数据库的了解和使用,同时提高自身的系统编程能力。
二、实验平台
开发工具:Qt creator 4.0.1(Qt版本:5.6.1 MSVC 2013,32bits)
数据库平台:MySQL5.7
实验平台:Windows10
三、总体设计
1、系统架构描述
本系统主要包括以下模块/功能:
(1)使用须知
(2)注册
(3)用户登录
(4)管理员登陆
(5)图书查询
(6)借书
(7)还书
(8)显示所有书籍
(9)新书入库
(10)书籍排序
(11)查看借阅情况
(12)查看用户表
(13)删除用户(收回权限)
其中(1)、(2)、(5)属于公用功能,也就是说,任何使用这款软件的人都可以查看使用须知、注册以及查询图书信息;(3)、(6)、(7)为用户设计,只有注册过的用户才能借书、还书。余下的模块/功能为管理员设计,是本系统中最复杂的部分。
需要说明的是,我没有设计管理员注册模块,因为在实际的应用情境中,显然不是随便一个人都能通过注册成为某个系统的管理员,所以,管理员权限由我这个"最高的管理员"直接在数据库中添加,从而防止了使用过程中可能出现的安全问题。
系统处理基本流程如下:
下面用表格的形式对各模块功能说明如下:
使用须知 |
点击后弹出使用须知。 |
注册 |
用于用户注册,供用户输入用户名、密码、并确认密码。只有注册后方可借书。 |
用户登录 |
用户登录。 |
管理员登陆 |
管理员登陆。 |
图书查询 |
可在输入栏中输入书籍名称,点击"点我搜索"按钮查询这本书的信息。(如果数据库中有这本书) |
借书 |
用于用户借书。 |
还书 |
用于用户还书。 |
显示所有书籍 |
进入管理员界面后方可使用,点击显示库存所有书籍。 |
新书入库 |
进入管理员界面后方可使用,可输入书籍信息,点击"提交书记入库信息"按钮完成新书入库。 |
书籍排序 |
进入管理员界面后方可使用,点击"书籍排序"按钮按库存量从小到大对书籍排序。方便管理员掌握书记库存情况。 |
查看借阅情况 |
进入管理员界面后方可使用,查看用户节约情况。 |
查看用户表 |
进入管理员界面后方可使用,查看注册的用户信息。 |
删除用户 |
进入管理员界面后方可使用,删除用户。 |
2、数据库表设计
数据库表设计是本次大作业中比较重要的一环,但是这个工作并不复杂。本次作业我新建了一个叫mybms(my book management system)的数据库,并定义了如下表格:
(1)管理员表(manager):
manager_name |
password |
其中manager_name是主键。各个属性从左到右依次表示:管理员名字、管理员密码。
(2)用户表(user):
user_name |
password |
其中user_name是主键。各个属性从左到右依次表示:用户名字、用户密码。
(3)书籍信息表(book):
book_id |
book_name |
author_name |
press_name |
price |
storage |
其中book_id是主键。各个属性从左到右依次表示:书籍编号、书名、作者名、出版社名、价格和库存量。
(4)借阅表(loan):
loan_id |
book_id |
book_name |
user_name |
其中loan_id是主键,book_id是外键,参照book表。各个属性从左到右依次表示:借阅编号、书籍编号、书名、用户名(即借阅者的名字)。
相关的SQL代码如下:
create database `mybms`;
use `mybms`;
create table `manager`(
`manager_name` varchar(15) primary key,
`password` varchar(20) not null
);
create table `user`(
`user_name` varchar(15) primary key,
`password` varchar(20) not null
);
create table `book`(
`book_id` char(5) primary key,
`book_name` varchar(20) not null,
`author_name` varchar(20),
`press_name` varchar(20),
`price` float,
`storage` int(12)
);
create table `loan`(
`loan_id` char(5) primary key,
`book_id` char(5),
`book_name` varchar(20),
`user_name` varchar(15),
foreign key(`book_id`) references `book`(`book_id`)
);
3、所用开发技术
(1)MySQL
MySQL是一款知名的开源关系型数据库管理系统,这次作业用到的MySQL的知识并不复杂,关键是要想清楚每张表需要什么数据以及每个数据的类型,为了配合Qt的QString类使用,我把大部分的数据都定义成了char。
(2)Qt
Qt本质上是一个C++的框架,用来写图形界面非常方便。使用Qt自己的IDE:QtCreator更加体现了Qt GUI编程的方便性。Qt Creator提供了所谓的"设计模式",在这个模式下程序员可以像画画一样用现成的控件进行布局,本程序的主界面就是用这种方式完成的。
四、详细设计
1.界面布局
1.1主界面
采用Qt Creator的设计模式布局,在QMainWindow类下包含了:QWidget、QPushButton、QLabel、QTabelView、QLineEdit等控件,其中QWidget是整个窗口,QPushButton是按钮,QLabel是标签,QTabelView是中间的表格,QLineEdit用来输入文字,可以被当成一个输入框。
为了界面的美观,添加了Qt资源文件(背景图)。实现背景效果的方法是:右键单击设计模式界面,选择"改变样式表",在选择资源选项中选中需要添加的图片,这里可以根据需要把图片设置成border-image或者background,我选择的是border-image。之后还有一个很重要的细节是,把当前窗口中的那行代码改成:#centralWidget{border-image: url(:/image/images/bkg_sea.png);}(如下图所示),它表示仅对centralWidget控件进行背景填充,这里的centralWidget是我自己起的名字,其实就是上文的QWidget。如果不这样设定的话,设计模式下的每个控件都会被填充上背景图,看上去非常丑。
1.2用户界面
如下图所示,用户登录以后进入用户界面:
(图被CSDN吃了)
界面提示用户使用图书管理系统要遵守的一些规定,在最下方,用户可以输入书名进行借阅或者归还,借阅成功、节约失败、归还成功、归还失败都会有相应的对话框提示。(由于这里是讲界面布局,所以具体功能将留到"3.功能实现"叙述)
实现这个界面的主要代码如下:
//用户界面
voidMainWindow::goto_ufunction_window(boolflag){
if(flag==0)
return;
else{
//必要的初始化
ufunction_window=newQWidget();
ufunction_warning_txtedit=newQTextEdit;
ufunction_borrow_lb=newQLabel;
ufunction_return_lb=newQLabel;
ufunction_borrow_le=newQLineEdit;
ufunction_return_le=newQLineEdit;
ufunction_borrow_btn=newQPushButton(tr("点击借阅"));
ufunction_return_btn=newQPushButton(tr("点击归还"));
ufunction_vblo_main=newQVBoxLayout;
ufunction_hblo_bottom=newQHBoxLayout;
//QTextEdit和QLabel的文字
ufunction_window->setWindowTitle(tr("您已进入用户界面"));
ufunction_warning_txtedit->setText(tr("尊敬的用户,为了您和他人的使用方便,请遵守以下规定:"
"\n"
"1、请勿损坏书籍;"
"\n"
"2、请勿逾期不还;"
"\n"
"3、如果违反,管理员有权注销您的借书权限!"));
ufunction_borrow_lb->setText(tr("输入需要借阅的书籍编号:"));
ufunction_return_lb->setText(tr("输入需要归还的书籍编号:"));
//布局
ufunction_hblo_bottom->addStretch();
ufunction_hblo_bottom->addWidget(ufunction_borrow_lb);
ufunction_hblo_bottom->addWidget(ufunction_borrow_le);
ufunction_hblo_bottom->addWidget(ufunction_borrow_btn);
ufunction_hblo_bottom->addStretch();
ufunction_hblo_bottom->addWidget(ufunction_return_lb);
ufunction_hblo_bottom->addWidget(ufunction_return_le);
ufunction_hblo_bottom->addWidget(ufunction_return_btn);
ufunction_hblo_bottom->addStretch();
//给布局添加控件
ufunction_vblo_main->addWidget(ufunction_warning_txtedit,Qt::AlignHCenter);
ufunction_vblo_main->addLayout(ufunction_hblo_bottom);
ufunction_window->setLayout(ufunction_vblo_main);
ufunction_window->resize(800,600);
ufunction_window->show();
//连接槽,负责借书、还书
connect(ufunction_borrow_btn,SIGNAL(clicked()),this,SLOT(ufunction_user_borrow()));
connect(ufunction_return_btn,SIGNAL(clicked()),this,SLOT(ufunction_user_return()));
}
}
代码采用水平布局和垂直布局相结合的方式,以垂直布局为主要布局实现了这个界面。最后的两个connect函数连接了控件:ufunction_borrow_btn(借书按钮)、ufunction_return_btn(还书按钮)相应的槽,将界面和功能模块联系了起来。
1.3管理员界面
如下图所示:
(图被CSDN吃了)
实现代码:
//管理员界面
voidMainWindow::goto_afunction_window(boolflag){
if(flag==0)
return;
else{
//必要的初始化
afunction_window=newQWidget();
afunction_add_btn=newQPushButton(tr("书籍入库"));//添加书籍
afunction_add_ok_btn=newQPushButton(tr("提交书籍入库信息"));
afunction_delete_btn=newQPushButton(tr("删除用户"));//删除用户
afunction_search_btn=newQPushButton(tr("搜索图书"));//搜索图书
afunction_show_all_btn=newQPushButton(tr("显示库中所有书籍"));//显示所有书籍
afunction_show_order_btn=newQPushButton(tr("按库存量排序(降序)"));
afunction_show_user_btn=newQPushButton(tr("显示用户表"));
afunction_show_loan_btn=newQPushButton(tr("显示借阅表"));
afunction_search_le=newQLineEdit;
afunction_tableview=newQTableView;
afunction_vblo_main=newQVBoxLayout;
afunction_hblo_sub1=newQHBoxLayout;
afunction_hblo_sub2=newQHBoxLayout;
afunction_hblo_sub3=newQHBoxLayout;
afunction_vblo_combine123=newQVBoxLayout;
afunction_window->setWindowTitle(tr("您当前处在管理员界面"));
afunction_tablemodel=newQSqlTableModel(afunction_window);
afunction_tablemodel->setTable("book");
//中间表格显示
afunction_tableview->setModel(afunction_tablemodel);
//布局添加控件
afunction_vblo_main->addWidget(afunction_tableview);
afunction_hblo_sub1->addWidget(afunction_search_le);
afunction_hblo_sub1->addWidget(afunction_search_btn);
afunction_hblo_sub1->addWidget(afunction_delete_btn);
afunction_hblo_sub2->addWidget(afunction_show_all_btn);
afunction_hblo_sub2->addWidget(afunction_show_order_btn);
afunction_hblo_sub2->addWidget(afunction_add_btn);
afunction_hblo_sub2->addWidget(afunction_add_ok_btn);
afunction_hblo_sub3->addWidget(afunction_show_user_btn);
afunction_hblo_sub3->addWidget(afunction_show_loan_btn);
//布局嵌套
afunction_vblo_combine123->addLayout(afunction_hblo_sub1);
afunction_vblo_combine123->addLayout(afunction_hblo_sub2);
afunction_vblo_combine123->addLayout(afunction_hblo_sub3);
afunction_vblo_main->addLayout(afunction_vblo_combine123);
//显示
afunction_window->setLayout(afunction_vblo_main);
afunction_window->resize(800,600);
afunction_window->show();
//连接槽
connect(afunction_search_btn,SIGNAL(clicked()),this,SLOT(afunction_search()));
connect(afunction_delete_btn,SIGNAL(clicked()),this,SLOT(afunction_delete()));
connect(afunction_show_all_btn,SIGNAL(clicked()),this,SLOT(afunction_show_all()));
connect(afunction_show_order_btn,SIGNAL(clicked()),this,SLOT(afunction_sort()));
connect(afunction_add_btn,SIGNAL(clicked()),this,SLOT(afunction_add()));
connect(afunction_add_ok_btn,SIGNAL(clicked()),this,SLOT(afunction_add_submit()));
connect(afunction_show_user_btn,SIGNAL(clicked()),this,SLOT(afunction_show_user()));
connect(afunction_show_loan_btn,SIGNAL(clicked()),this,SLOT(afunction_show_loan()));
}
}
这个布局相对而言复杂一点,三个水平布局需要加到一个垂直布局,然后再把这个垂直布局加到另一个垂直布局。
2.连接数据库
连接数据库部分的代码虽然不多,但是着实折腾了好一阵。
按照常规的做法,需要在Qt的.pro文件中加入代码:QT+= core gui sql,然后将MySQL的libmysql.dll文件放到Qt的工程根目录下,如下图所示:
Qt已经为用户提供了功能强大的数据库相关模块,在完成以上步骤后,将需要用到的模块include进来,如:
#include<QSqlDatabase>
#include<QSqlQuery>
#include<QtSql>
#include<QSqlTableModel>
#include<QSqlRelationalTableModel>
#include<QSqlError>
其中QSqlDatabase、QSqlQuery、QtSql是完成数据库操作所必须的。
之后再定义连接数据库的函数:
boolMainWindow::createConnection(){
//连接MySQL数据库
db=QSqlDatabase::addDatabase("QMYSQL");
//设置主机名
db.setHostName("localhost");
//设置数据库名
db.setDatabaseName("mybms");
//设置账号名
db.setUserName("xxx");
//设置密码名
db.setPassword("csdbs");
//设置端口
db.setPort(3306);
if(!db.open()){
QMessageBox::critical(0,QObject::tr("error"),db.lastError().text());
returnfalse;
}
}
这个函数需要在MainWindow的构造函数里调用。
当然,最后也要考虑到断开数据库连接的问题,只需要在MainWindow的析构函数里调用:db.removeDatabase("mybms");就可以了。此处的db是自己起的变量名,本质上是一个QSqlDatabase对象,"mybms"是数据库的名字。removeDatabase函数是Qt自己提供的,不需要用户自己实现。
但是,按如上步骤做遇到了问题,发现数据库连接不上,经过查阅资料后发现原来是32位的Qt与64位的MySQL不兼容。解决的方法是:在Qt官网上下载名为mysql-connector-c-6.1.9-win32的补丁,将它解压之后,在对应的文件夹下找到libmysql.dll文件,然后将这个文件放进Qt工程根目录就可以了。(这里有两个libmysql.dll,需要用connector生成的那个)
3.功能实现
为了方便演示,先在MySQL Workbench中输入如下SQL代码:
insert into `manager` values('manager01','123456');
insert into `user` values('user01','123456');
insert into `book` values
('01','C++程序设计','孟宪福','清华大学出版社',28.00,5),
('02','C++ Primer','Stanley B.Lippman','人民邮电出版社',99.00,5),
('03','浮士德','歌德','人民文学出版社','65.00',4),
('04','简明法语教程','孙辉','外研社','28.80',5),
('05','Linear Algebra','Gilbert Strang','高等教育出版社',32.50,6);
通过以上代码,我添加了一个叫manager01的管理员,密码是123456,一个叫user01的用户,密码是123456,我插入了5本书,它们的详细信息如上。下面在这些信息的基础上说明具体的功能实现:
3.1图书查询
在初始界面的输入栏中输入想要查找的书,比如:C++ Primer,点击"点我搜索",就可以查询到这本书的信息。当然,查询成功的前提是数据库中要有这本书,如果没有这本书,搜索结果将不予显示。
主要的实现代码:
voidMainWindow::on_query_btn_clicked(){
QStringbook_name=ui->name_lineEdit->text();
model->setFilter(QString("book_name='%1'").arg(book_name));
model->select();
}
Qt的QTableView模块使得查询变得非常方便。使用setFilter函数、select函数和使用SQL的select...from...where...语句是等价的。同时还有一个便利是这样做可以不用区分大小写,也就是说不管是输入C++ Primer还是c++ PriMeR......都能够查找到结果,这和设计的预期比较一致。
3.2使用须知
主要的实现代码:
//使用须知的槽
voidMainWindow::on_notice_btn_clicked(){
notice_window=newQWidget();
notice_vblo=newQVBoxLayout;
notice_head=newQLabel;
notice_line1=newQLabel;
notice_line2=newQLabel;
notice_line3=newQLabel;
notice_line4=newQLabel;
notice_line5=newQLabel;
notice_line6=newQLabel;
notice_head->setText(tr("尊敬的用户,欢迎您使用图书管理系统,以下是使用须知:\n"));
QFontfont_head("MicrosoftYaHei",15,75);
notice_head->setFont(font_head);
notice_line1->setText(tr("1.。。。\n"));
QFontfont1(0,15,0);
notice_line1->setFont(font1);
notice_line2->setText(tr("2.。。。\n"));
QFontfont2(0,15,0);
notice_line2->setFont(font2);
notice_line3->setText(tr("3.。。。\n"));
QFontfont3(0,15,0);
notice_line3->setFont(font3);
notice_line4->setText(tr("4.。。。\n"));
QFontfont4(0,15,0);
notice_line4->setFont(font4);
notice_line5->setText(tr("5.。。。\n"));
QFontfont5(0,15,0);
notice_line5->setFont(font5);
notice_line6->setText(tr("6.如有任何问题,请联系:xxx\n"));
QFontfont6(0,15,0);
notice_line6->setFont(font6);
//给布局添加控件
notice_vblo->addWidget(notice_head);
notice_vblo->addWidget(notice_line1);
notice_vblo->addWidget(notice_line2);
notice_vblo->addWidget(notice_line3);
notice_vblo->addWidget(notice_line4);
notice_vblo->addWidget(notice_line5);
notice_vblo->addWidget(notice_line6);
//显示
notice_window->setLayout(notice_vblo);
notice_window->resize(800,600);
notice_window->show();
}
3.3用户注册
点击用户注册按钮进行用户注册将会出现如下对话框:
(图被CSDN吃了)
用户可以设置自己的用户名和密码,密码需要二次输入以便确认。如果填写的信息不完整,比如,有一个用户只填写了用户名:excited!而没有填写密码,如下图:
(图被CSDN吃了)
那么这样搞肯定是不行的,程序将给出警告:
(图被CSDN吃了)
如果用户输入的密码不一致,比如:
(图被CSDN吃了)
将给出警告:
(图被CSDN吃了)
而如果信息填完整了,密码两次输入也没有问题,但是这个名字已经被注册了,显然也不行,将给出警告:
(图被CSDN吃了)
如果注册成功,将给出提示:
(图被CSDN吃了)
主要的实现代码:
voidMainWindow::user_register(){
//检测用户是否输入了全部的信息
if(register_name_le->text().isEmpty()||register_pwd_le->text().isEmpty()
||register_pwd_check_le->text().isEmpty()){
QMessageBox::critical(NULL,"Error",tr("您填写的信息不完整"),QMessageBox::Yes);
return;
}
//检测密码是否一致
if(register_pwd_le->text().compare(register_pwd_check_le->text())!=0){
QMessageBox::critical(NULL,"Error",tr("两次密码输入不一致!"),QMessageBox::Yes);
return;
}
//查询用户名是否已存在于数据库
QSqlQueryquery;
query.exec("selectuser_namefromuserwhereuser_name='"+register_name_le->text()+"'");
if(query.next()){
QMessageBox::critical(NULL,"Error",tr("该用户名已被注册"),QMessageBox::Yes);
return;
}
//向user表中插入用户信息
query.exec("insertintouservalues('"+register_name_le->text()+"','"+register_pwd_check_le->text()+"')");
if(query.isActive()){
QMessageBox::about(0,"mybms",tr("注册成功!"));
register_window->close();//注册成功之后将注册窗口关闭
}
else{
QMessageBox::critical(NULL,"Error",tr("注册失败"),QMessageBox::Yes);
return;
}
}
3.4用户登录
用户通过用户登录进入用户功能界面,用户登录界面如下:
(图被CSDN吃了)
如果登陆成功或者失败,同样会有和上面类似的警告或者提示,这里就不重复贴图了。
主要的实现代码:
voidMainWindow::user_login(){
booluser_login_success_flag=0;//一开始设为零表示登录不成功
QSqlQueryquery;
//根据用户输入的用户名,在user表中查询其密码
query.exec("selectpasswordfromuserwhereuser_name='"+ulogin_name_le->text()+"'");
if(!query.isActive()){
return;
}
//判断密码是否与结果一致
if(query.next()){
QStringuser_pwd=query.value(0).toString();
if(QString::compare(user_pwd,ulogin_pwd_le->text())==0){
user_login_success_flag=1;
ulogin_window->close();
}
else{
QMessageBox::critical(NULL,"Error","密码错误",QMessageBox::Yes);
return;
}
}
//如果数据库中没有此用户名,给出警告
else{
QMessageBox::critical(NULL,"Error","该用户名不存在",QMessageBox::Yes);
return;
}
goto_ufunction_window(user_login_success_flag);//去到用户界面
}
3.5借书
借书的界面如下:
(图被CSDN吃了)
用户可以输入书籍的编号进行借书,这个编号可以在一开始的主界面查询比如输入05,对应的书是Linear Algebra,如果借阅成功会显示:
(图被CSDN吃了)
否则显示:
(图被CSDN吃了)
如果同一个用户对一本书进行多次借阅,则会给出警告:
(图被CSDN吃了)
这样就避免了某些用户重复借阅给他人带来不便。
借书本质上是对数据库中的book表做一个查询,如果能找到用户需要的书,就把这条记录插入loan表,同时更新book表的信息。
主要的实现代码:
//借书
voidMainWindow::ufunction_user_borrow(){
//先检查这本书有没有被当前用户借过
QSqlQuerycheck_query;
check_query.exec("selectbook_id,user_namefromloanwherebook_id='"+ufunction_borrow_le->text()+"'");
if(check_query.next()){
QStringcheck_name=check_query.value(1).toString();
if(check_name==ulogin_name_le->text()){
QMessageBox::critical(NULL,"Error",tr("每本书只能借一次!"),QMessageBox::Yes);
return;
}
}
QSqlQueryquery;
boolfind_ok_flag=0;
query.exec("selectbook_id,book_namefrombookwherebook_id='"+ufunction_borrow_le->text()+"'");
if(!query.isActive()){
return;
}
if(query.next()){
QStringbook_id=query.value(0).toString();
QStringbook_name=query.value(1).toString();
if(QString::compare(book_id,ufunction_borrow_le->text())==0){
find_ok_flag=1;
query.exec("updatebooksetstorage=storage-1wherebook_id='"+ufunction_borrow_le->text()+"'");
user_borrow_id_int++;
user_borrow_id=QString::number(user_borrow_id_int,10);
query.exec("insertintoloanvalues('"+user_borrow_id+"','"+book_id+"','"+book_name+"','"+ulogin_name_le->text()+"')");
QMessageBox::about(0,tr("数据库反馈"),tr("借书成功!"));
}
}
else{
QMessageBox::critical(NULL,"Error","借阅失败,请检查您的拼写!",QMessageBox::Yes);
}
}
3.6还书
还书与借书类似,同样需要输入书籍编号,再点击"点击归还",归还成功会提示:
(图被CSDN吃了)
还书其实是在操作loan表和book表,loan表中book_id与用户输入相同的记录需要被delete掉,同时book表中相同book_id的书籍信息也需要更新。
主要的实现代码:
//还书
voidMainWindow::ufunction_user_return(){
QSqlQueryquery;
boolreturn_ok_flag=0;
query.exec("selectloan_id,book_idfromloanwherebook_id='"+ufunction_return_le->text()+"'");
if(!query.isActive()){
return;
}
if(query.next()){
QStringloan_id=query.value(0).toString();
QStringbook_id=query.value(1).toString();
if(QString::compare(book_id,ufunction_return_le->text())==0){
return_ok_flag=1;
query.exec("updatebooksetstorage=storage+1wherebook_id='"+ufunction_return_le->text()+"'");
query.exec("deletefromloanwhereloan_id='"+loan_id+"'");
QMessageBox::about(0,tr("数据库反馈"),tr("归还成功,感谢您的使用!"));
}
}
else{
QMessageBox::critical(NULL,"Error","归还失败,请检查您的拼写!",QMessageBox::Yes);
}
}
3.7管理员登陆
管理员登陆界面如下,和用户登录界面类似:
(图被CSDN吃了)
登陆成功、登录失败都会有相应的提示,效果和前面展示的类似,这里从略。
主要的实现代码:
voidMainWindow::admin_login(){
booladmin_login_success_flag=0;
QSqlQueryquery;
//根据用户输入的用户名,在manager表中查询其密码
query.exec("selectpasswordfrommanagerwheremanager_name='"+alogin_name_le->text()+"'");
if(!query.isActive()){
return;
}
//判断密码是否与结果一致
if(query.next()){
QStringadmin_pwd=query.value(0).toString();
if(QString::compare(admin_pwd,alogin_pwd_le->text())==0){
admin_login_success_flag=1;
alogin_window->close();
}
else{
QMessageBox::critical(NULL,"Error","密码错误",QMessageBox::Yes);
return;
}
}
//如果数据库中没有此用户名,给出警告
else{
QMessageBox::critical(NULL,"Error","该管理员不存在",QMessageBox::Yes);
return;
}
goto_afunction_window(admin_login_success_flag);//去到管理员界面
}
3.8显示所有书籍
如下图所示,点击"显示库中所有书籍"可以看到当前数据库中所有的书。
(图被CSDN吃了)
主要的实现代码:
//显示所有图书
voidMainWindow::afunction_show_all(){
afunction_tablemodel->setTable("book");
afunction_tablemodel->select();
}
3.9书籍排序
为了方便管理员了解每本书的库存量,加入了书籍排序功能。点击"按库存量排序(降序)",将会得到如下图所示的结果,可以看到此时数据库中的书籍都按照storage的大小从小到大排好序了:
(图被CSDN吃了)
这主要是为了方便管理员添加书籍,避免出现storage不够的情况。
主要的实现代码:
//排序
voidMainWindow::afunction_sort(){
afunction_tablemodel->setSort(5,Qt::AscendingOrder);
afunction_tablemodel->select();
}
代码中的参数5表示排序的对象是第5列,第二个参数指定了排序方式:ascending。
3.10新书入库
管理员不需要直接操作数据库,仅仅通过这个程序就可以添加书籍信息,这本质上是在对数据库的book表做insert操作。
当处在显示书籍的界面时,点击"书籍入库",会在表上增加一行,管理员可以在这一行里输入新书的信息。比如现在需要添加一本叫做《C++:从入门到放弃》的书,效果如下图所示:
(图被CSDN吃了)
编辑过程中,如果没有点击"提交书籍入库信息",则在这一行的前面会一直有一个*号表示当前处在编辑的状态,确定无误后,即可点击"提交书籍入库信息"进行提交,这样就可以完成书籍入库了。
点击书籍入库按钮后也可以对原来的书籍信息进行修改,但是只要不提交,数据库都不会接收到这个变化。
主要的实现代码:
//添加书籍
voidMainWindow::afunction_add(){
introw_num=afunction_tablemodel->rowCount();
QStringbook_id;
afunction_tablemodel->insertRow(row_num);
afunction_tablemodel->setData(afunction_tablemodel->index(row_num,0),book_id);
//afunction_tablemodel->submitAll();
}
//提交添加书籍的修改
voidMainWindow::afunction_add_submit(){
afunction_tablemodel->database().transaction();
if(afunction_tablemodel->submitAll()){
if(afunction_tablemodel->database().commit())
QMessageBox::information(this,tr("数据库反馈"),tr("书籍入库成功!"));
}
else{
afunction_tablemodel->database().rollback();
QMessageBox::warning(this,tr("数据库反馈"),
tr("发生错误:%1").arg(afunction_tablemodel->lastError().text()),
QMessageBox::Ok);
}
}
3.11查看借阅情况
管理员可以查看书籍的借阅情况,其实就是访问之前定义过的loan表。在管理员功能界面点击"显示借阅表"即可看到当前的loan_id、book_id、book_name、user_name等信息,如下图所示:
(图被CSDN吃了)
主要的实现代码:
//显示loan表
voidMainWindow::afunction_show_loan(){
afunction_tablemodel->setTable("loan");
afunction_tablemodel->select();
}
3.12管理用户(查看、删除)
管理员可以对用户进行管理,包括查看用户信息(用户名和密码),以及取消某些不守规矩的用户的借阅权限,也就是把用户从user表给删掉。
例如在当前的界面下选中user02这一行,然后点击"删除用户"按钮,将会弹出警告对话框,如下图所示:
(图被CSDN吃了)
主要的实现代码:
//删除
voidMainWindow::afunction_delete(){
intcur_row=afunction_tableview->currentIndex().row();
intok=QMessageBox::warning(this,tr("删除这个用户"),tr("您确定删除当前行吗?"),
QMessageBox::Yes,QMessageBox::No);
if(ok==QMessageBox::Yes){
afunction_tablemodel->removeRow(cur_row);
afunction_tablemodel->submitAll();
}
else
return;
}
currentIndex函数获取了当前行,removeRow函数可以将某行记录删掉,数据库信息被修改后需要调用submitAll函数提交,只有执行了这个函数才会真的影响到外部连接的MySQL数据库,否则删除无效。
五、实验心得
。。。