工程实训纪

选题:PC端记账本软件
语言:C++
开发工具:Qt库、Qt Creator
其实组里的人都比较懒,做完了之后觉得应该做个游戏什么的比较考验自己的能力,不过做实用的软件也确实比较有意思,为此还买了个机械键盘,感觉有点浪费hhh,下面开始正题了。
软件要实现的几个主要功能

  1. 记录每日支出

  2. 实现简单的本地登录功能->即实现数据库的写入与读取
    我在这里用的是Qt自带的一个比较简单的QSQLite,有需求的可以上远程服务器,不过我这里还是遇到了一些问题就是在打包之后无法使用数据库,可能是依赖没有添加的原因,由于已经蒙混过关了所以就没有深究这一块的问题。

  3. 实现支出数据的图表化

总体看下来个人认为比较繁琐的是数据库的部分,巧的是我之前做的一个项目里有比较接近的模块,所以这部分是我自己来负责的,零零总总还都比较简单,由于队友都不太行hhhh,我也就没想着做拓展功能,谁能想到五个人的团队实际上只有两个人在写代码呢?

1
2
3
4
5
6
7
8
9
10
bool OpenDateBase();
int main(int argc, char *argv[])
{
OpenDateBase();
QApplication a(argc, argv);
MainWindow w;
w.show();

return a.exec();
}

可以看到main部分的代码还是比较简单的,大概是实现这么一个逻辑:打开数据库,生成窗口实例,展示窗口最后再让窗口一直显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
bool OpenDateBase(){
QSqlDatabase mydb=QSqlDatabase::addDatabase("QSQLITE");
mydb.setDatabaseName("cashitem.db");
if(mydb.open())
{
qDebug()<<"open success";
QSqlQuery query;
//新建item表,id设置为主键,一个金额,一个类型,一个内容,一个时间
query.exec("create table item(id INTEGER PRIMARY KEY AUTOINCREMENT,money int,type varchar,content varchar,addtime time,useraccount varchar)");//条目,即输入的支出数据
query.exec("create table user(id INTEGER PRIMARY KEY AUTOINCREMENT,useraccount varchar,userpassword varchar,useremail varchar)");//用户信息
query.exec("create table user_budget_setting(id INTEGER PRIMARY KEY AUTOINCREMENT,useraccount varchar,dayBudget int,monthBudget int,yearBudget int)");//用户的支出与预算表
return true;
}
else
{
//给出debug提示,便于定位错误的地点
qDebug()<<"open failed";
return false;
}
}

必须在Qt给出的.pro文件中添加sql,见下文的最后一行

1
2
3
4
5
6
7
#-------------------------------------------------
#
# Project created by QtCreator 2019-07-03T10:40:19
#
#-------------------------------------------------

QT += core gui sql charts

这一部分的代码我是根据网上的一篇博客改的,在这里我先创建了一个数据库,若数据库存在那么就会直接调用,这里的数据库使用还是比较轻松的,以前我用服务器的数据库真的是一波三折哈哈哈,而后创建了三张数据表,含义在我给的注释里。
这个主键我也是纠结了很久,我以为给他传一个NULL就好了,后来我发现还不能加‘’单引号确实比较坑爹,详细可以看我后面给出的代码。
接下来是主窗口的代码mainwindow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
tagWidgetLayout.setParent(ui->dailyBoardContent);
connect(&user_login,&userLoginWindow::loginSuccess,this,&MainWindow::user_login_sucess);
connect(&itemMark,&itemMark::conveyData,this,&MainWindow::addNewItemLabel);
ui->edit_pushButton->hide();
ui->delet_pushButton_2->hide();
ui->statusBar->hide();
ui->menuBar->hide();
ui->mainToolBar->hide();
}

MainWindow::~MainWindow()//主窗口的销毁函数
{
QSqlQuery query;//建立一个数据库的query
QString sql1;
sql1="insert into user_login(id,useraccount)values(NULL,'') ";
query.exec(sql1);
query.exec("select id,useraccount from user_login where id >= 0");
while (query.next()) {
QString id = query.value(0).toString();
useraccount = query.value(1).toString();
qDebug()<<"mainwindow:"<tabWidget->hide();
itemMark.show();
}

void MainWindow::addNewItemLabel(int money ,QString type,QString content){
newWidget = new itemWidget(money,type,content,ui->itemListWidget);
QSqlQuery query1;
query1.exec("select id,useraccount from user_login where id >= 0");
while (query1.next()) {
QString id = query1.value(0).toString();
useraccount = query1.value(1).toString();
qDebug()<itemListWidget,0);
listwidgetitem->setSizeHint(QSize(50,50));
ui->itemListWidget->setItemWidget(listwidgetitem,newWidget);
ui->itemListWidget->show();
}

}
void MainWindow::deletItem(){
QListWidgetItem *listwidgetitem= ui->itemListWidget->currentItem();
listwidgetitem->setHidden(true);
}

void MainWindow::on_userAvatarPic_clicked()
{
user_login.show();
}

void MainWindow::on_dailyBoardButton_clicked()
{
ui->stackedWidget->setCurrentIndex(0);
}

void MainWindow::on_chartAnalysisButton_clicked()
{
int i = ui->monthSelector->currentIndex();
chartsMaking(i+1);
ui->stackedWidget->setCurrentIndex(1);
}

void MainWindow::on_bugetSettingButton_clicked()
{
QSqlQuery query_user;
query_user.exec("select id,useraccount from user_login where id >= 0");
while(query_user.next()){
useraccount = query_user.value(1).toString();
// qDebug()<stackedWidget->setCurrentIndex(2);

QSqlQuery query;
QDateTime dtm;
QString timeNow=dtm.currentDateTime().toString("yyyyMMdd");
int year = timeNow.toInt();
// int day = year % 100;
year/=100;
// int month = year % 100;
year/=100;
int thisMonthCost(0),thisDayCost(0),thisYearCost(0);
QString monthNow = timeNow.remove(6,7);
timeNow=dtm.currentDateTime().toString("yyyyMMdd");
QString sql =QString("select money,addtime,useraccount from item where addtime between '%1%2%3'and '%4%5%6'").arg(year).arg("01").arg("01").arg(year+1).arg("01").arg("00");
query.exec(sql);
while(query.next()){
if (query.value(2).toString() == useraccount) {
thisYearCost+=query.value(0).toInt();
if (query.value(1).toString().contains(monthNow,Qt::CaseInsensitive)) thisMonthCost+=query.value(0).toInt();
if (query.value(1).toString() == timeNow ) thisDayCost+=query.value(0).toInt();
}
}
//qDebug()<dayBudget)//TODO 增加弹窗提示
{
ui->dayprogressBar->setMaximum(thisDayCost);
}
else ui->dayprogressBar->setMaximum(dayBudget);

if (thisMonthCost>monthBudget)//TODO 增加弹窗提示
{
ui->monthprogressBar->setMaximum(thisMonthCost);
}
else ui->monthprogressBar->setMaximum(monthBudget);

if (thisYearCost>yearBudget)//TODO 增加弹窗提示
{
ui->yearprogressBar->setMaximum(thisYearCost);
}
else ui->yearprogressBar->setMaximum(yearBudget);

ui->dayprogressBar->setValue(thisDayCost);
ui->monthprogressBar->setValue(thisMonthCost);
ui->yearprogressBar->setValue(thisYearCost);


QString daylabel = QString("每日预算:%1/%2").arg(thisDayCost).arg(dayBudget);
QString monthlabel = QString("每月预算:%1/%2").arg(thisMonthCost).arg(monthBudget);
QString yearlabel = QString("每年预算:%1/%2").arg(thisYearCost).arg(yearBudget);
ui->dayBudgetSetlabel->setText(daylabel);
ui->monthBudgetSetlabel->setText(monthlabel);
ui->yearBudgetSetlabel->setText(yearlabel);
}

void MainWindow::on_dayBudgetSetButton_clicked()
{
//接收新的预算
int dayBudget;
dayBudget = QInputDialog::getInt(this,"设置","每日预算:",0);
QSqlQuery query;
QSqlQueryModel *model_2 = new QSqlQueryModel;
QString sql = QString("select count (*) from user_budget_setting where useraccount = '%1'").arg(useraccount);
model_2->setQuery(sql);
QModelIndex index1 = model_2->index(0,0);
if (index1.data()==0){//插入一条新记录
sql = QString("insert into user_budget_setting(id,dayBudget,monthBudget,yearBudget,useraccount) values(NULL,'%1','%2','%3','%4')").arg(dayBudget).arg(0).arg(0).arg(useraccount);
qDebug()<dayprogressBar->value()).arg(dayBudget);
ui->dayBudgetSetlabel->setText(daylabel);
if (ui->dayprogressBar->value()>dayBudget)//TODO 增加弹窗提示
{
ui->dayprogressBar->setMaximum(ui->dayprogressBar->value());
}
else ui->dayprogressBar->setMaximum(dayBudget);
ui->dayBudgetSetlabel->show();

}

void MainWindow::on_monthBudgetSetButton_clicked()
{
//接收新的预算
int monthBudget;
monthBudget = QInputDialog::getInt(this,"设置","每月预算:",0);
//TODO添加数据库操作
QSqlQuery query;
QSqlQueryModel *model_2 = new QSqlQueryModel;
QString sql = QString("select count (*) from user_budget_setting where useraccount = '%1'").arg(useraccount);
model_2->setQuery(sql);
QModelIndex index1 = model_2->index(0,0);
if (index1.data()==0){//插入一条新记录
sql = QString("insert into user_budget_setting(id,dayBudget,monthBudget,yearBudget,useraccount) values(NULL,'%1','%2','%3','%4')").arg(0).arg(monthBudget).arg(0).arg(useraccount);
qDebug()<monthprogressBar->value()).arg(monthBudget);
ui->monthBudgetSetlabel->setText(monthlabel);
if (ui->monthprogressBar->value()>monthBudget)//TODO 增加弹窗提示
{
ui->monthprogressBar->setMaximum(ui->monthprogressBar->value());
}
else ui->monthprogressBar->setMaximum(monthBudget);

ui->monthBudgetSetlabel->show();
}

void MainWindow::on_yearBudgetSetButton_clicked()
{
//接收新的预算
int yearBudget;
yearBudget = QInputDialog::getInt(this,"设置","每年预算:",0);
//TODO添加数据库操作
QSqlQuery query;
QSqlQueryModel *model_2 = new QSqlQueryModel;
QString sql = QString("select count (*) from user_budget_setting where useraccount = '%1'").arg(useraccount);
model_2->setQuery(sql);
QModelIndex index1 = model_2->index(0,0);
if (index1.data()==0){//插入一条新记录
sql = QString("insert into user_budget_setting(id,dayBudget,monthBudget,yearBudget,useraccount) values(NULL,'%1','%2','%3','%4')").arg(0).arg(0).arg(yearBudget).arg(useraccount);
qDebug()<yearprogressBar->value()).arg(yearBudget);
ui->yearBudgetSetlabel->setText(yearlabel);
if (ui->yearprogressBar->value()>yearBudget)//TODO 增加弹窗提示
{
ui->yearprogressBar->setMaximum(ui->yearprogressBar->value());
}
else ui->yearprogressBar->setMaximum(yearBudget);
ui->yearBudgetSetlabel->show();
}


void MainWindow::on_monthSelector_activated(int index)
{
int x = index;
x++;
chartsMaking(x);
}

//饼状图生成函数
void MainWindow::chartsMaking(int month)
{
QSqlQuery query1;
query1.exec("select id,useraccount from user_login where id >= 0");
while (query1.next()) {
QString id = query1.value(0).toString();
useraccount = query1.value(1).toString();
qDebug()<<"BarMaking:"<append("饮食",eatMoney);
series->append("娱乐",entertainmentMoney);
series->append("教育",eduMoney);
series->setLabelsVisible();

/*QPieSlice *slice_red = series->slices().at(0);
QPieSlice *slice_green = series->slices().at(1);
QPieSlice *slice_blue = series->slices().at(2);
slice_red->setColor(QColor(255,0,0,255));
slice_green->setColor(QColor(0,255,0,255));
slice_blue->setColor(QColor(0,0,255,255));*/

QChart *chart = new QChart();
chart->addSeries(series);
QString title = QString("您的%1月的账单统计图").arg(month);
chart->setTitle(title);
chart->legend()->hide();
ui->chartViewer->setChart(chart);
//QChartView *chartview = new QChartView(chart);
//chartview->setRenderHint(QPainter::Antialiasing);

//chartview->resize(400,400);
//chartview->show();

//ui->graphicsView->setChart(chart);
//ui->graphicsView->setRenderHint(QPainter::Antialiasing);
}
//柱状图生成函数
void MainWindow::barChartsMaking(int month){
QSqlQuery query1;
query1.exec("select id,useraccount from user_login where id >= 0");
while (query1.next()) {
QString id = query1.value(0).toString();
useraccount = query1.value(1).toString();
qDebug()<<"BarMaking:"<append(set);
//series->append(setEntertainment);
//series->append(setEdu);
QChart *chart = new QChart();
QString title = QString("您的%1月的账单统计图").arg(month);
chart->setTitle(title);

QBarCategoryAxis *axis = new QBarCategoryAxis();
axis->append(category);
chart->createDefaultAxes();

chart->addSeries(series);
chart->setAxisX(axis,series);
ui->chartViewer->setChart(chart);
}

void MainWindow::on_delet_pushButton_2_clicked()
{
QListWidgetItem *listwidgetitem= ui->itemListWidget->currentItem();
listwidgetitem->setHidden(true);
QSqlQuery query;
int curRow = ui->itemListWidget->currentIndex().row(); //鼠标选择删除第几行
QModelIndex index = ui->itemListWidget->currentIndex();
int id=index.sibling(curRow,0).data().toInt();
QString str =QString("delete from item where id = '%1'").arg(curRow) ;
query.exec(str);
}
//编辑按钮
void MainWindow::on_edit_pushButton_clicked()
{
QSqlQuery query;
query.exec("select id,money,type,content,addtime from item where id >= 1");
QString str;
QString str1;
QString str2;
QString str3;
QString str4;
QString str5;
QDateTime dtm;
int dtm0;
while(query.next())
{
//query.value(0)是id的值,将其转换为int型

//QString str0 = dtm.toString("yyyy-mm-dd hh:mm:ss");
str1 = query.value(0).toString();
str2 = query.value(1).toString();
str3 = query.value(2).toString();
str4 = query.value(3).toString();
str5 = query.value(4).toString();
//输出两个值
qDebug() << str1<< str2<< str3<< str4<itemListWidget->clear();
}
void MainWindow::user_login_sucess(){

QSqlQuery query1;
query1.exec("select id,useraccount from user_login where id >= 0");
while (query1.next()) {
QString id = query1.value(0).toString();
useraccount = query1.value(1).toString();
qDebug()<<"mainwindow:"<itemListWidget->clear();
while (query1.next()) {
QString id = query1.value(0).toString();
int money = query1.value(1).toInt();
QString type = query1.value(2).toString();
QString content = query1.value(3).toString();
useraccount = query1.value(5).toString();
newWidget = new itemWidget(money,type,content,ui->itemListWidget);
QListWidgetItem *listwidgetitem = new QListWidgetItem(ui->itemListWidget,0);
listwidgetitem->setSizeHint(QSize(50,50));
ui->itemListWidget->setItemWidget(listwidgetitem,newWidget);
ui->itemListWidget->show();
qDebug()<monthSelector->currentIndex();
chartsMaking(index+1);
}

void MainWindow::on_selectLinerChart_clicked()
{
int index;
index = ui->monthSelector->currentIndex();
barChartsMaking(index+1);
}

接下来是用户登录的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "userloginwindow.h"
#include "ui_userloginwindow.h"
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;


userLoginWindow::userLoginWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::userLoginWindow)
{
ui->setupUi(this); this->setWindowTitle(" ");

//注册页面
ui->userID_reg->setPlaceholderText("请输入用户名");

ui->userPassword_reg->setPlaceholderText("密码");
ui->userPassword_reg_2->setPlaceholderText("确认密码");
ui->userPassword_reg->setEchoMode(QLineEdit::Password);
ui->userPassword_reg_2->setEchoMode(QLineEdit::Password);

ui->userMail->setPlaceholderText("xxx@xxx.xxx");
//注册操作
connect(ui->reg_button,&QPushButton::clicked,this,&userLoginWindow::sendToDateBase_regist);
//登陆操作
connect(ui->loginButton,&QPushButton::clicked,this,&userLoginWindow::sendToDateBase_log);
//登录界面
ui->username->setPlaceholderText("请输入用户名");
ui->userPassword->setEchoMode(QLineEdit::Password);
ui->userPassword->setPlaceholderText("请输入密码");
}

userLoginWindow::~userLoginWindow()
{
delete ui;
}


void userLoginWindow::on_registerButton_clicked()
{
ui->log->hide();
ui->reg->show();
}

void userLoginWindow::on_return_button_clicked()
{
ui->log->show();
ui->reg->hide();
}
void userLoginWindow::sendToDateBase_regist(){
QSqlQuery query;
QString sql;
QString str1 ,str2, str3;
str1 = ui->userID_reg->text();
str2 = ui->userPassword_reg->text();
str3 = ui->userMail->text();
QSqlQueryModel *model1=new QSqlQueryModel;
sql = QString("select count (*) from user where useraccount = '%1'").arg(str1);
model1->setQuery(sql);
QModelIndex index1=model1->index(0,0);
//query.exec(sql);
if(index1.data()==0){
//如果这条数据不存在那么插入这条数据
sql = QString("insert into user(id, useraccount, userpassword,useremail) values(NULL,'%1', '%2', '%3')").arg(str1).arg(str2).arg(str3);
query.exec(sql);
//debug测试
query.exec("select id,useraccount,userpassword,useremail from user where id >= 1");
while(query.next())
{
//query.value(0)是id的值,将其转换为int型

//QString str0 = dtm.toString("yyyy-mm-dd hh:mm:ss");
str1 = query.value(1).toString();
str2 = query.value(2).toString();
str3 = query.value(3).toString();

//输出两个值
qDebug() << str1<< str2<< str3 ;
}
qDebug()<<"注册成功";
ui->userID_reg->clear();
ui->userPassword_reg->clear();
ui->userPassword_reg_2->clear();
ui->userMail->clear();
ui->reg->hide();
ui->log->show();
}else{
qDebug()<<"用户已存在";
}
}
void userLoginWindow::sendToDateBase_log(){
QSqlQuery query;
QString sql;
QString str1 ,str2, str3;
str1 = ui->username->text();//用户输入的用户名
str2 = ui->userPassword->text();//用户输入的密码
QSqlQueryModel *model1=new QSqlQueryModel;
QSqlQueryModel *model2=new QSqlQueryModel;
sql = QString("select count (*) from user where useraccount = '%1'").arg(str1);
model1->setQuery(sql);
QModelIndex index1=model1->index(0,0);
if(index1.data()==0){
qDebug()<<"用户名不存在";
}else{
//获取该用户名下的密码进行对比
sql=QString("select userpassword from user where useraccount = '%1'").arg(str1);
model2->setQuery(sql);
QModelIndex index2=model2->index(0,0);
if(index2.data()==str2){
query.exec("create table user_login(id INTEGER PRIMARY KEY AUTOINCREMENT ,useraccount varchar)");//这张表是为了获取当前登录的用户,并以此来确定各个模块的显示
sql = QString("insert into user_login(id,useraccount) values(NULL,'%1')").arg(str1);
query.exec(sql);
qDebug()<<"userlogwindow:"<username->clear();
ui->userPassword->clear();
this->close();
qDebug()<<"登陆成功";
}else{
qDebug()<<"密码错误";
}
}
}

void userLoginWindow::regUser()
{
int user_num_int;
qint64 pos;
QFile file("userAccout.txt");
bool isOk = file.open(QIODevice::ReadWrite|QIODevice::Text);
if (isOk == true){
pos=file.size();
QString user_num = file.readLine();
QTextStream txtout(&file);
for (int i=0;iuserID_reg->text()<userPassword_reg->text()<userMail->text()<log->show();
ui->reg->hide();

ui->userID_reg->clear();
ui->userPassword_reg->clear();
ui->userPassword_reg_2->clear();
ui->userMail->clear();
}

最后做完了整个项目后反思了一下,有这么几个做的不太好:
用户登录之后没有更改登录的状态显示,导致直接可以登录第二个用户,后期偷懒没有把这个做成更加美观的解决方案
很多地方都重复的使用了相同的代码,下一次可以试着做成一个简单的调用函数,降低各个版块之间的耦合度。
在做用户支出条目的时候没有实现条目的增删查改,只完成了条目的输入和清空,原因是我发现删改在QListWidget里实现比较麻烦,在翻阅了他的官方文档后他提示我要使用QListView,但那时已经接近项目结束了所以就没有重写。
最后一点就是有时候我太放心别人写的东西了,要保持自己怀疑的心。
最后放上我的GitHub地址:TankNee’s Repo -CashBook
万分感谢各位合作的队友们

Author: TankNee
Link: https://www.tanknee.cn/2019/07/24/%E5%B7%A5%E7%A8%8B%E5%AE%9E%E8%AE%AD-%E8%AE%B0%E8%B4%A6%E8%BD%AF%E4%BB%B6/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.