数据结构课程设计
(一)需求和规格说明
问题描述:设计一个中英文字典查询系统。如给出中文“苹果”,能查询出其对应的英文单词“apple”。
编程任务:
1)自建系统的词库和存储结构,以方便更好的进行查询;
2)该系统在一定的权限控制下具有基本的查询、增加、删除、修改功能,并尽可能的保证良好的时间开销;
(1)查询操作时应考虑精确查询和模糊查询;
(2)增加操作时:该程序输入一个英语单词,若该单词不存在,可向词库添加该词和释义(应考虑一个单词可以有多个释义);
3)实现输入输出交互界面。
(二)设计
1.问题分析
对于构建课设要求的电子词库,我们必须解决以下几个问题,
- 数据的存储(2)数据的增删改查(3)美观的交互界面
我们来进行逐个分析:
(1)数据的存储:我首先想到的是使用红黑树,即C++STL中的map容器,其具有高性能的查找功能,存储方面也可以单独建立一个词库文件,利用C++文档流读取文件来创建我们的词库红黑树,这确实是一个可选择项。
不过本次课设的最终方案还是选择了MySQL数据库作为存储策略,目的是学习搭建QT调用mysql的环境、在QT中进行SQL的增删改查操作,而且使用数据库比较方便,我也可以在mysql的图形化编辑工具DataGrip中实时地查看词库建立地情况,对于一个电子词典的编辑是非常便利的。
当然,首要问题其实是环境的配置,没有在QT中导入mysql的话就什么都做不了。我们需要利用对应版本QT源码文件夹插件包中有关于sql驱动“sqldriver”插件库下的mysql.pro文件进行代码修改,将mysql服务的路径导入,并构筑工程文件,从而构建起QT与mysql的动态链接库.dll文件,再将同等级路径下生成的动态链接库文件放入QT的插件文件夹下,才能满足后续的编译需求。这一部分我会在答辩视频中进行详细的讲解。
环境配置后,就是怎么在QT中调用mysql进行数据的增删改查,这本质是第(2)个问题,而第(1)个问题中我们亟待解决的问题仍然有如下几个:
第一步:建立自己的词库数据集,我先是在百度文档中查找到了《大学英语词汇库》将其导入execl文件中,通过execl的操作将其整理成两列。其中一列是英文,另一列则是它的翻译。然后通过execl的拼接函数CONCAT批量化生成SQL插入语句,并用DataGrip在我的数据库中新建一个dictionary表,并将生成的插入语句全部执行,全部插入到dictionary表中。这样就完成了数据集的搭建。
使用execl批量生成SQL插入语句。
在DG中将批量生成的SQL语句全部执行插入。
SQL语句执行完毕,我们就完成了数据集的构建,词库的导入,之后就可以使用SQL语句来不断进行维护了。
数据的增删改查:
数据的增删改查,我们选择在QT中执行SQL语句,这里就涉及到SQL的导入,
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("127.0.0.1"); //连接本地主机,也可以写localhost,或写电脑域名。
db.setPort(3306);
db.setDatabaseName("test");
db.setUserName("dictionary");//grant all on test.* to 'dictionary'@'%';所有权限已给
db.setPassword("2394485232");//密码就是作者的QQ哒
我们通过QsqlDatabase类来实例化一个数据库对象,用来链接我的MySQL,这里我已经在DG中创建了一个可以在任意别的主机打开的用户,并且授予了该用户对于我的test数据库的增删改查全部权限。
下面分模块并结合UI界面进行课设作品的介绍与代码实现:
首先我们再看一遍题目要求:
1)自建系统的词库和存储结构,以方便更好的进行查询;
2)该系统在一定的权限控制下具有基本的查询、增加、删除、修改功能,并尽可能的保证良好的时间开销;
(1)查询操作时应考虑精确查询和模糊查询;
(2)增加操作时:该程序输入一个英语单词,若该单词不存在,可向词库添加该词和释义(应考虑一个单词可以有多个释义);
3)实现输入输出交互界面。
题目要求简洁,主界面如上所示,其mainwindow代码实现则如下:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle("dictionary_ver_wyuu");
ui->lineEdit->setFont(QFont("宋体",13));
ui->pushButton->setFont(QFont("宋体",12));
// ui->pushButton_2->setFont(QFont("宋体",13));
// ui->pushButton_3->setFont(QFont("宋体",13));
// ui->pushButton_4->setFont(QFont("宋体",13));
// ui->pushButton_5->setFont(QFont("宋体",13));
ui->textBrowser->setFont(QFont("宋体",11));
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("127.0.0.1"); //连接本地主机,也可以写localhost,或写电脑域名。
db.setPort(3306);
db.setDatabaseName("test");
db.setUserName("dictionary");//grant all on test.* to 'dictionary'@'%';所有权限已给
db.setPassword("2394485232");//密码就是作者的QQ哒
bool ok =
db.open();
if (ok){
QMessageBox::information(this, "提示", "服务器连接成功");
}
else {
QMessageBox::information(this, "提示", "服务器连接失败");
qDebug()<<"error open database because"<<db.lastError().text();
}
}
MainWindow::~MainWindow()
{
delete ui;
db.close();
}
<1>在翻译按钮实现的槽函数中,是这样的逻辑设计,先利用我们强大的正则表达式来检测输入的字符串中有没有汉字,然后根据输入的汉字还是英文分为两种处理模式,其中如果输入的是汉字,会用%占位符来进行模糊搜索的实现。
QString target ="'%"+ ui->lineEdit->text() +"%'";
QString sql = "select * from dictionary where translation like "+ target;
而输入的是英语,就不会考虑到模糊搜索而是直接拼接好需要的SQL语句并进行执行。
QString target ="'"+ ui->lineEdit->text() +"'";
QString sql = "select * from dictionary where English = "+ target;
搜索到的结果通过
while (query.next()) {
qDebug()<< query.value(1).toString()
<< query.value(2).toString();
English = query.value(1).toString();
translation = query.value(2).toString();
qDebug()<< English;
qDebug()<< translation;
}
来进行获取,并打印在UI界面的文本框内。
整体槽函数代码如下:
void MainWindow::on_pushButton_clicked()
{
QString targetline = ui->lineEdit->text();
bool b = targetline.contains(QRegExp("[\\x4e00-\\x9fa5]+"));
QSqlQuery query(db);
if(b)
{
//qDebug()<<"存在中文";
QString target ="'%"+ ui->lineEdit->text() +"%'";
QString sql = "select * from dictionary where translation like "+ target;
qDebug()<< sql;
query.exec(sql);
QString English="";
QString translation="";
while (query.next()) {
qDebug()<< query.value(1).toString()
<< query.value(2).toString();
English = query.value(1).toString();
translation = query.value(2).toString();
qDebug()<< English;
qDebug()<< translation;
}
if(English=="")
{
ui->textBrowser->append("抱歉,词库中暂时没有,欢迎您编辑该词条!");
}
ui->textBrowser->append(English);
ui->textBrowser->append(translation);
}
else
{
QString target ="'"+ ui->lineEdit->text() +"'";
QString sql = "select * from dictionary where English = "+ target;
query.exec(sql);
QString English="";
QString translation="";
while (query.next()) {
qDebug()<< query.value(1).toString()
<< query.value(2).toString();
English = query.value(1).toString();
translation = query.value(2).toString();
}
if(English=="")
{
ui->textBrowser->append("抱歉,词库中暂时没有,欢迎您编辑该词条!");
}
ui->textBrowser->append(English);
ui->textBrowser->append(translation);
}
}
<2>清空
void MainWindow::on_pushButton_2_clicked()
{
ui->lineEdit->setText("");
ui->textBrowser->setText("");
}
<3>打开增加词条界面
void MainWindow::on_pushButton_3_clicked()
{
update_vocabulary * configWindow = new update_vocabulary;
configWindow->show();
}
<4>打开删除词条界面
void MainWindow::on_pushButton_4_clicked()
{
fix_vocabulary * configWindow2 = new fix_vocabulary;
configWindow2->show();
}
<5>打开修改词条界面
void MainWindow::on_pushButton_5_clicked()
{
modify_vocabulary * configWindow3 = new modify_vocabulary;
configWindow3->show();
}
后面的3、4、5其实就是打开一个新界面,下面对3、4、5点进行分点详细论述介绍。
首先是3,增加词条:
在增加词条中,实现底层逻辑就是获取用户在文本框内输入的文本,然后进行一定的字符串拼接方式,拼接成插入的SQL语句。
SQL的插入,即为INSERT INTO关键字来实现,其实与我在数据存入时是一样的语法
其代码实现如下(为节省篇幅,在构造函数中连接MySQL与UI相关不再显示)
void update_vocabulary::on_pushButton_clicked()
{
QSqlQuery query(db);
QString English = ui->lineEdit->text();
QString translation = ui->lineEdit_2->text();
QString sql = "insert into dictionary(English,translation) values('" +English+ "','"+translation+"')";
query.exec(sql);
this->close();
}
就是简单的获取两个参数,然后拼接成一条SQL语句来执行。
query.exec(sql);
4是删除词条
删除词条使用的SQL语句是:
其关键字为DELETE。
Ui界面如下:
如果删除我的数据库中没有的词条,会导致闪退,其代码实现如下:(为节省篇幅,在构造函数中连接MySQL与UI相关不再显示)
void fix_vocabulary::on_pushButton_clicked()
{
QString target ="'"+ ui->lineEdit->text() +"'";
qDebug()<<target;
QSqlQuery query(db);
QString sql = "delete from dictionary where English = "+ target;
qDebug()<<sql;
query.exec(sql);
this->close();
}
在文本框中获取目标词条的英文用来定位,然后使用DELETE关键字拼接为删除指令的SQL语句执行即可。
5.修改词条
修改词条使用的SQL语句是:
使用的关键字是UPDATE 。
UI界面如下:
代码逻辑是通过最上面的文本框来获取英文,然后在下面的两个文本框进行修改,其实现代码如下
void modify_vocabulary::on_pushButton_clicked()
{
QSqlQuery query(db);
QString former ="'"+ ui->lineEdit->text() + "'";
QString English2 = "'"+ui->lineEdit_2->text()+ "'";
QString translation ="'"+ ui->lineEdit_3->text()+"'";
//update employee set dept_id=3 where id=3;
QString sql = "update dictionary set English = "+ English2 + " where English = "+ former;
query.exec(sql);
QString sql2 = "update dictionary set translation = "+ translation + "where English = "+ former;
query.exec(sql2);
this->close();
}
总之这里就是拼接了SQL语句执行,写课设报告时发现这里两句应该可以并作一句,这样还可以提高执行效率,代码需要进一步的优化!
总之这里也是拼成了SQL语句去执行。
三个小模块是一模一样的逻辑。
以上就是(2)和(3)的设计总体介绍。
2.设计思想
(1)首先构思一下该软件的各个方面的大致实现,以及规划一下需要设计的模块。文件架构如下:
其中在QT的插件库中还需要有MySQL驱动的动态链接库文件。
这两个动态链接库文件是必要放在QT插件库下的。
总的来说C:\Qt\Qt5.14.2\5.14.2\mingw73_64\plugins\sqldrivers文件下应该是有这五个动态链接库的
不然就无法完成环境的配置。
其余问题其实都已经在问题分析中做过详细阐述了,我将在答辩视频中做进一步汇报。
(三)用户手册
(1)程序需要借由MySQL服务器运行,在使用该程序前,请确保您的主机上具备MySQL服务。
(2)其他提示可以参考UI界面的tips
Tips:
修改词条:在最上方文本框中输入目标词条的英文用来在数据库中定位此词条,然后在下方两个文本框中分别添加修改后的英文及其译文。
Tips:
删除词条:在下面的文本框中输入目标词条英文,点击删除词条即可
请不要删除数据库中没有的词条,当你查到某个词条觉得它不合理的时候再考虑删除并修改
等..
( 3 ) 作者初学MySQL,程序实现可能不尽如人意,只能实现基本的增删改查,没有像代码输入时的用户提示功能或是扩展搜索框功能,后续我会继续努力,争取添加这些效果的。
(四)调试及测试
1. 部分程序运行截图
主界面截图:
修改词条界面截图:
删除词条界面截图:
修改词条界面截图:
- 测试数据
目前共收录3083个词,其实还远远不够,可以考虑继续收集数据,扩充数据集。
3. 测试结果
支持模糊搜索,而且时间效率较高。
4. 进一步改进
(1)数据集较小,词汇量不够大。
(2)不支持扩展搜索框以及提示工具。
(3)对于用户的门槛较高,要求对方也具备MySQL提供的服务。之后可以考虑嵌入式开发(开玩笑的,就是一个U盘),来存储数据集。
(五) 感想
在这次课设中用到的技术栈对于我来说还真是不少的,老师也对我说一旦牵扯到实际开发对技术的要求就是这样的,我也深有感悟,虽然这样一个小项目确实不能算是到达实际开发的门槛,而且我实现的项目也存在一些问题,但是我真的收获了很多新的知识,包括我用整整三天的时间,学习了SQL操作的基础篇,也就是增删改查。确实这个项目用到的SQL语句的逻辑其实都是最基础的。并没有涉及到分页查询和多表联查中的内连接、外连接、联合查询、子查询等复杂的查询语法,也没有涉及到并发事务处理等业务逻辑,但是作为对于我数据库学习的一个小总结我认为是可以的,因为它也确实帮助我加深了对于SQL语法的记忆,比方说DCL语言,这一部分我在听课的时候是没有着重去听的,但是后来做项目的过程中发现DCL是必不可少要熟练使用的。
总而言之,完成这样一个小项目是比较自豪激动的,感谢老师特地留下这么一个感想板块T-T。
附录:
代码量并不多,且基本已在问题分析环节展现
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle("dictionary_ver_wyuu");
ui->lineEdit->setFont(QFont("宋体",13));
ui->pushButton->setFont(QFont("宋体",12));
// ui->pushButton_2->setFont(QFont("宋体",13));
// ui->pushButton_3->setFont(QFont("宋体",13));
// ui->pushButton_4->setFont(QFont("宋体",13));
// ui->pushButton_5->setFont(QFont("宋体",13));
ui->textBrowser->setFont(QFont("宋体",11));
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("127.0.0.1"); //连接本地主机,也可以写localhost,或写电脑域名。
db.setPort(3306);
db.setDatabaseName("test");
db.setUserName("dictionary");//grant all on test.* to 'dictionary'@'%';所有权限已给
db.setPassword("2394485232");//密码就是作者的QQ哒
bool ok =
db.open();
if (ok){
QMessageBox::information(this, "提示", "服务器连接成功");
}
else {
QMessageBox::information(this, "提示", "服务器连接失败");
qDebug()<<"error open database because"<<db.lastError().text();
}
}
MainWindow::~MainWindow()
{
delete ui;
db.close();
}
void MainWindow::on_pushButton_clicked()
{
QString targetline = ui->lineEdit->text();
bool b = targetline.contains(QRegExp("[\\x4e00-\\x9fa5]+"));
QSqlQuery query(db);
if(b)
{
//qDebug()<<"存在中文";
QString target ="'%"+ ui->lineEdit->text() +"%'";
QString sql = "select * from dictionary where translation like "+ target;
qDebug()<< sql;
query.exec(sql);
QString English="";
QString translation="";
while (query.next()) {
qDebug()<< query.value(1).toString()
<< query.value(2).toString();
English = query.value(1).toString();
translation = query.value(2).toString();
qDebug()<< English;
qDebug()<< translation;
}
if(English=="")
{
ui->textBrowser->append("抱歉,词库中暂时没有,欢迎您编辑该词条!");
}
ui->textBrowser->append(English);
ui->textBrowser->append(translation);
}
else
{
QString target ="'"+ ui->lineEdit->text() +"'";
QString sql = "select * from dictionary where English = "+ target;
query.exec(sql);
QString English="";
QString translation="";
while (query.next()) {
qDebug()<< query.value(1).toString()
<< query.value(2).toString();
English = query.value(1).toString();
translation = query.value(2).toString();
}
if(English=="")
{
ui->textBrowser->append("抱歉,词库中暂时没有,欢迎您编辑该词条!");
}
ui->textBrowser->append(English);
ui->textBrowser->append(translation);
}
}
void MainWindow::on_pushButton_2_clicked()
{
ui->lineEdit->setText("");
ui->textBrowser->setText("");
}
void MainWindow::on_pushButton_3_clicked()
{
update_vocabulary * configWindow = new update_vocabulary;
configWindow->show();
}
void MainWindow::on_pushButton_4_clicked()
{
fix_vocabulary * configWindow2 = new fix_vocabulary;
configWindow2->show();
}
void MainWindow::on_pushButton_5_clicked()
{
modify_vocabulary * configWindow3 = new modify_vocabulary;
configWindow3->show();
}
#include "fix_vocabulary.h"
#include "ui_fix_vocabulary.h"
fix_vocabulary::fix_vocabulary(QWidget *parent) :
QWidget(parent),
ui(new Ui::fix_vocabulary)
{
ui->setupUi(this);
setWindowTitle("编辑词条");
ui->lineEdit->setFont(QFont("宋体",13));
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("127.0.0.1"); //连接本地主机,也可以写localhost,或写电脑域名。
db.setPort(3306);
db.setDatabaseName("test");
db.setUserName("dictionary");
db.setPassword("2394485232");
db.open();
}
fix_vocabulary::~fix_vocabulary()
{
delete ui;
db.close();
}
void fix_vocabulary::on_pushButton_clicked()
{
QString target ="'"+ ui->lineEdit->text() +"'";
qDebug()<<target;
QSqlQuery query(db);
QString sql = "delete from dictionary where English = "+ target;
qDebug()<<sql;
query.exec(sql);
this->close();
}
#include "modify_vocabulary.h"
#include "ui_modify_vocabulary.h"
modify_vocabulary::modify_vocabulary(QWidget *parent) :
QWidget(parent),
ui(new Ui::modify_vocabulary)
{
ui->setupUi(this);
ui->lineEdit_2->setFont(QFont("宋体",13));
ui->lineEdit_3->setFont(QFont("宋体",13));
ui->lineEdit->setFont(QFont("宋体",13));
setWindowTitle("编辑词条");
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("127.0.0.1"); //连接本地主机,也可以写localhost,或写电脑域名。
db.setPort(3306);
db.setDatabaseName("test");
db.setUserName("dictionary");
db.setPassword("2394485232");
db.open();
}
modify_vocabulary::~modify_vocabulary()
{
delete ui;
}
void modify_vocabulary::on_pushButton_clicked()
{
QSqlQuery query(db);
QString former ="'"+ ui->lineEdit->text() + "'";
QString English2 = "'"+ui->lineEdit_2->text()+ "'";
QString translation ="'"+ ui->lineEdit_3->text()+"'";
//update employee set dept_id=3 where id=3;
QString sql = "update dictionary set English = "+ English2 + " where English = "+ former;
query.exec(sql);
QString sql2 = "update dictionary set translation = "+ translation + "where English = "+ former;
query.exec(sql2);
this->close();
}
#include "update_vocabulary.h"
#include "ui_update_vocabulary.h"
update_vocabulary::update_vocabulary(QWidget *parent) :
QWidget(parent),
ui(new Ui::update_vocabulary)
{
ui->setupUi(this);
setWindowTitle("编辑词条");
ui->lineEdit->setFont(QFont("宋体",13));
ui->lineEdit_2->setFont(QFont("宋体",13));
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("127.0.0.1"); //连接本地主机,也可以写localhost,或写电脑域名。
db.setPort(3306);
db.setDatabaseName("test");
db.setUserName("dictionary");
db.setPassword("2394485232");
db.open();
}
update_vocabulary::~update_vocabulary()
{
delete ui;
db.close();
}
void update_vocabulary::on_pushButton_clicked()
{
QSqlQuery query(db);
QString English = ui->lineEdit->text();
QString translation = ui->lineEdit_2->text();
QString sql = "insert into dictionary(English,translation) values('" +English+ "','"+translation+"')";
query.exec(sql);
this->close();
}