本打算昨天计划完成“复习页面”的程序逻辑,晚上就让孩子们完成第一天复习计划,但昨天遇到了一些困难,SO,今天继续。
重新对需求进行分析
面对“按记忆曲线复习”这个命题,我好像已经很清楚怎么做了。但真正开始时,却有点想不清楚了:
我在设计表时,“复习表” 和 “录入单词表” 是两张表,这样做的原因是,有的单词需要多次进入复习计划中,而我希望达到“一次录入多次复习”的目标。这就引发了一个问题:什么时候“单词表”中的单词 进入到“复习表”中?
梳理方案 :当打开“当天待识记内容”功能点时,昨天录入的单词自动导入到“复习表”中?这样好像并不完美,原因:
<1> 如果第二天孩子并没有打开“当天待识记内容”功能点呢?
<2> 如果昨天并没有录入单词,而前天录入的又很多呢?
如此,还不如把所有未导入复习计划的单词全展现出来,让孩子挑呢。这样让孩子更主动,更愿意接受。似乎能确定“进入复习计划”第一步的需求了。
问题又来了,“当天待识记内容” 功能点只有一个,显示让孩子挑选当天复习内容需要一个页面,而复习听写又需要一个页面。
所以,挑选动作需要增加一个弹窗,选择完以后,再进入当天的复习环节,而复习的内容除了刚挑选入复习计划的单词外,还有往日复习计划中当天需要识记的内容。
OK,思路清晰了!
接下来就是听写计划内单词,听写加上得分环节,可以激发出孩子的竞争动力。
对于那些听写不通过的单词,标识为NoPass!
1、增加一个弹窗
形如:
该窗口是一个Dialog对话框,在建这个widget时,不能选择成Main Window,否则主窗口打开这个弹窗时,就达不到预期效果。
2、选择单词进入复习计划列表
在走向目标的过程中,遇到了 两个问题 ,先记录下来:
问题1:怎么知道操作人员选择了哪些行?
【答案】self.ui.tableView.selectionModel().selectedRows(),可以得到一个index列表,这些index有一个row()属性,可以帮助我们获取选中的行号。
问题2:有了行号怎么得到word_id
【答案】self.qrModel.record(行号).value(列号)
再说这个弹窗主要功能的实现:
因为这是一个独立的弹窗,该页面上的功能可以在自己的逻辑窗口内完成,所以,可以借助 全局变量 完成写数据库的操作了。详细如下:
2.1显示未入复习计划的知识点
stu_id = myGlobValues.get_value('G_stu_id')
self.qrModel = QSqlQueryModel(self)
self.qrModel.setQuery(
"SELECT a.word_id as '单词ID', picture as '图片', word as '字词', means as '意思',input_day as '录入时间' "
" FROM words a "
" WHERE stu_id = '" + stu_id + "'and not exists (select 1 from memory b WHERE b.word_id = a.word_id) "
" ORDER BY sub_id")
self.ui.tableView.setModel(self.qrModel)
self.ui.tableView.setColumnHidden(0, True)
2.2 提交已选中的知识进入复习计划
代码如下:
indexs = self.ui.tableView.selectionModel().selectedRows()
for idx in indexs:
word_id = self.qrModel.record(idx.row()).value(0)
# 找出lastRow, 用于生成不重复的word_id
qr = QSqlQuery(self.db)
qr.exec("select max(rowid) as myrowid from memory")
qr.last()
if qr.value('myrowid') == '': # 新数据库会是这样的情况 没有一条记录
lastRow = 1
else:
qr.exec("select max(mem_id) as max_id from memory")
qr.last()
lastRow = qr.value('max_id') + 1
# 找出 total_rows 用于插入记录时的定位
qr.exec("select count(*) as total_rows from memory")
qr.last()
total_rows = qr.value('total_rows')
qr.finish()
self.tableModelMemory.insertRow(total_rows, QModelIndex())
curRec = self.tableModelMemory.record() # 只有表头
curRec.setValue('mem_id', lastRow)
curRec.setValue('word_id', word_id)
curRec.setValue('first_time', QDate.currentDate())
self.tableModelMemory.setRecord(total_rows, curRec) # 插入记录
if self.tableModelMemory.submitAll():
print('插入记录成功')
3、显示当天需要复习的知识点
在此,我又遇到一些问题:
问题1:怎样将str型的日期,转为QDate类型的日期?
. .解释:从数据库中获取的时间是str类型的,而使用QDate.currentDate() 得到时间是QDate类型的。
【答案】:
Date.fromString(self.qrModel.record(row).value(column),‘yyyy-MM-dd’)
问题2:两个日期怎么相减?
想到的第一个方法就是两个日期直接相减,结果报错了。查找了一下QDate的方法,发现有一个addDays(),于是就用了这样的方法解决:
【答案】:判断 {小日期.addDays(n) } 是否是大日期相等。
QDate.fromString(self.qrModel.record(0).value(4),'yyyy-MM-dd').addDays(2) == QDate.currentDate()
不一定是最佳解决方案,但可以往下进行了!耶!
问题3: 以上两个方法,在sql中都不能用,sql中的时间怎么对比?
【答案】用字段名=当前时间减天数的字符串形式,形如:
first_time= QDate.currentDate().addDays(-天数).toString(‘yyyy-MM-dd’)
经历过对以上问题的思考,最终使用以下查询完成了“待复习内容”的查询:
self.qrModel = QtSql.QSqlQueryModel(self)
self.qrModel.setQuery(
"SELECT a.word_id as '单词ID', picture as '图片', word as '字词', means as '意思',first_time as '首次复习时间' "
" FROM memory a , words b "
" WHERE a.word_id = b.word_id and stu_id = '" + self.stu_id + "' and sub_id ='" + kemu_id + "' and ("
"first_time= '" + QDate.currentDate().addDays(-1).toString('yyyy-MM-dd')
+ "' or first_time= '" + QDate.currentDate().addDays(-2).toString('yyyy-MM-dd')
+ "' or first_time= '" + QDate.currentDate().addDays(-6).toString('yyyy-MM-dd')
+ "' or first_time= '" + QDate.currentDate().addDays(-14).toString('yyyy-MM-dd')
+ "' or first_time= '" + QDate.currentDate().addDays(-30).toString('yyyy-MM-dd')
+ "' or first_time= '" + QDate.currentDate().toString('yyyy-MM-dd') +
"') ORDER BY a.word_id desc ")
self.ui.tableView.setModel(self.qrModel)
最后的显示结果如下: