这次更新变化还是比较大的,一是增加听写功能,从1至25按顺序给小朋友按,听写好就按下是否听写正确。二是提醒功能,如果超过30秒、60秒、90秒不按(即不做题)就用声音提醒小朋友做题。三是采集2700多个小学生生字的部首,在无声出题时帮助小朋友选择字,这里还有个更新就是出题是会连续三个界面的字相同,但出题的顺序不同,无声出题是第一次是拼音加2组词,第二次是拼音加部首加一组词,第三次是部首加2组词。
一、采集www.cidianso.com网站的部首及笔画动画gif源代码:
# -*- coding: utf-8 -*-
"""
Created on Sun May 19 15:19:17 2024
@author: YBK
"""
import urllib
import sqlite3
from urllib.request import urlopen,Request
import urllib,string
from bs4 import BeautifulSoup as bf
from time import time, sleep
import random
db_filepath = 'D:\\bee\\qwrz2\\src\\qwrz2\\resources\\qwrznew.db'
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
i = 0
while i < 2272:
cursor = c.execute("SELECT id,hz FROM hz WHERE bh is Null limit 0,1;")
row = cursor.fetchone()
hzid = row[0]
strzi = row[1]
url = f"https://www.cidianso.com/{strzi}_zi/"
url = urllib.parse.quote(url, safe=string.printable)
html = urlopen(url)
# 获取的html内容是字节,将其转化为字符串
html_text = bytes.decode(html.read())
obj = bf(html_text,'html.parser')
index_hotlist = obj.find_all('div',class_='small_nanex new_li')
for div in index_hotlist:
divxx = div.find_all('img')
for p in divxx:
if p.get('src'):
zisrc = p.get('src')
index_hotlist = obj.find_all('div',class_='name')
py = []
for div in index_hotlist:
if strzi + '的部首' in div.get_text():
bs = div.get_text().replace(strzi + '的部首','').strip(' ')
if strzi + '的拼音' in div.get_text():
ahrf = div.find_all('a')
for ahr in ahrf:
py.append(ahr.get_text())
#py = div.get_text().replace(strzi + '的拼音','').strip('\n').strip(' ').strip('')
if strzi + '的笔画' in div.get_text():
bh = div.get_text().replace(strzi + '的笔画','').strip(' ')
if strzi + '的笔顺' in div.get_text():
bshun = div.get_text().replace(strzi + '的笔顺','').strip(' ')
py1 = ''
py1 = str.join(",", py)
image_url='https://www.cidianso.com'+zisrc
urllib.request.urlretrieve(image_url,'E:\\7777\\zigif\\'+str(hzid)+'.gif')#网址、存储路径
print(strzi,py1,bs,bh,bshun)
if len(bshun)>0:
c.execute("UPDATE hz SET bs = ?,pys = ?,bh = ?,bshun = ? WHERE id = ?;", (bs,py1,bh,bshun,hzid))
conn.commit()
i = i + 1
sleep(random.randint(1,2))
c.close()
conn.close()
二、主程序源代码:
from functools import partial
import toga
from toga.style.pack import COLUMN, LEFT, RIGHT, ROW, Pack
#from toga.fonts import Font
import sqlite3
import random
from time import time, sleep
from pathlib import Path
import miniaudio
import datetime
import threading
from threading import Timer
import shutil
#导入必要的库,其中这个miniaudio库是可以在Android上运行的,我尝试了很多播放声音的库,只有这个能被Beeware编译到安卓程序上
resources_folder = Path(__file__).joinpath("../resources/").resolve()
resources_folder1 = Path(__file__).joinpath("../resources/sy1").resolve()
resources_folder2 = Path(__file__).joinpath("../resources/sy2").resolve()
resources_folder3 = Path(__file__).joinpath("../resources/sy3").resolve()
giffolder = Path(__file__).joinpath("../resources/gif").resolve()
#Font.register('simkai',str(resources_folder.joinpath("simkai.ttf")))
#注册楷体simkai,这个在电脑上能用但手机上就不行了
#方便测试我这里写了个变量sjcs,1为手机,0为电脑,2为boox平板
db_filepath = resources_folder.joinpath("qwrznew.db")
sjcs = 0
if sjcs == 1:
sj_file = '/data/data/com.qwrz.qwrz2/qwrz.db'
if Path(sj_file).exists():
db_filepath = sj_file
else:
shutil.copy(db_filepath, sj_file)
db_filepath = sj_file
elif sjcs == 2:
db_filepath = '/storage/emulated/0/Pictures/qwrznew.db'
#使用手机将数据库存放在手机的/data/data/文件夹中,不用获取权限,减少麻烦,我以前的版本是放在文档中方便分析数据
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
cursor = c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='tx'")
row = cursor.fetchone()
have_tx = row[0]
if have_tx ==0:
c.execute('''CREATE TABLE tx (
tid INTEGER PRIMARY KEY AUTOINCREMENT,
nj INTEGER,
hid INTEGER REFERENCES hz (id),
cid INTEGER REFERENCES record (cid),
times INTEGER DEFAULT (0)
);
''')
conn.commit()
#创建听写表,用于记录听写信息
cursor = c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='setupme'")
row = cursor.fetchone()
have_set = row[0]
if have_set ==0:
c.execute('''CREATE TABLE setupme (
have_record2 INTEGER,
have_jfen INTEGER,
set_gz INTEGER,
g16_fs INTEGER,
g16_width INTEGER,
g16_height INTEGER,
g25_fs INTEGER,
g25_width INTEGER,
g25_height INTEGER,
app_name TEXT);
''')
conn.commit()
c.execute("INSERT INTO setupme(app_name,g25_height,g25_width,g25_fs,g16_height,g16_width,g16_fs,set_gz,have_jfen,have_record2) VALUES ('千纬认字(听写版)',68,68,22,85,85,25,16,0,0);")
conn.commit()
cursor = c.execute("SELECT app_name,g25_height,g25_width,g25_fs,g16_height,g16_width,g16_fs,set_gz,have_jfen,have_record2 FROM setupme")
row = cursor.fetchone()
globals()['app_name'] = row[0]
globals()['g25_height'] = row[1]
globals()['g25_width'] = row[2]
globals()['g25_fs'] = row[3]
globals()['g16_height'] = row[4]
globals()['g16_width'] = row[5]
globals()['g16_fs'] = row[6]
globals()['set_gz'] = row[7]
globals()['have_jfen'] = row[8]
globals()['have_record2'] = row[9]
else:
cursor = c.execute("SELECT app_name,g25_height,g25_width,g25_fs,g16_height,g16_width,g16_fs,set_gz,have_jfen,have_record2 FROM setupme")
row = cursor.fetchone()
globals()['app_name'] = row[0]
globals()['g25_height'] = row[1]
globals()['g25_width'] = row[2]
globals()['g25_fs'] = row[3]
globals()['g16_height'] = row[4]
globals()['g16_width'] = row[5]
globals()['g16_fs'] = row[6]
globals()['set_gz'] = row[7]
globals()['have_jfen'] = row[8]
globals()['have_record2'] = row[9]
#创建setupme表,用于记录app的有关参数,这个是以前做网站的经验,这样有利于让app多功能
if globals()['have_record2'] == 0:
cursor = c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='record2'")
row = cursor.fetchone()
have_record2a = row[0]
if have_record2a == 0:
c.execute('''
CREATE TABLE record2 (
rid INTEGER PRIMARY KEY AUTOINCREMENT,
hid INTEGER REFERENCES hz (id),
cid INTEGER REFERENCES record (cid),
yt INTEGER);
''')
conn.commit()
c.execute("update setupme set have_record2 = 1")
conn.commit()
else:
c.execute("update setupme set have_record2 = 1")
conn.commit()
#是否存在record2表,没有就建表,并在参数表设置为1,该表用于记录答题时长
if globals()['have_jfen'] == 0:
cursor = c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='jfen'")
row = cursor.fetchone()
have_jfena = row[0]
if have_jfena == 0:
c.execute('''CREATE TABLE jfen (
jid INTEGER PRIMARY KEY AUTOINCREMENT,
rq TEXT,
jf INTEGER);
''')
conn.commit()
c.execute("update setupme set have_jfen = 1")
conn.commit()
else:
c.execute("update setupme set have_jfen = 1")
conn.commit()
#是否存在jfen表,没有就建表,并在参数表设置为1,下次就不要判断是否有这个表
current_date = datetime.datetime.now()
formatted_date = current_date.strftime("%Y-%m-%d")
cursor = c.execute("SELECT count(*) FROM jfen WHERE rq='"+ formatted_date +"'")
row = cursor.fetchone()
if row[0] == 0:
query_sql = "INSERT INTO jfen (rq,jf) VALUES (?,?);"
c.execute(query_sql, (formatted_date,0,))
conn.commit()
c.close()
conn.close()
#在积分表中写入今天的一行,用于记录今天的积分
global duihz, duipy, duizc1, duizc2, duizc3,duizc4,duizc5, duid, kw, jj
global stime, etime, ytime, begintime, testcs, cuo_cs, yshen, cid, tjcs
names = globals()
cid = 0
yshen = 0
rongy = 0 #实际是用于听写,不是容易
testtime = 0 #用于记录测试次数,每16-25个字测试3次
testcs = 0
cuo_cs = 0
stime = time()
begintime = time()
rid = 0
cuot = 0
duid = 0
jf = 0
kn = 0
jj = ''
zjf = 0
global njt,njt1
njt = '一年级'
#上面是全局参数和默认值
def bfsy(hzid,idsc):
if hzid < 1001:
stream = miniaudio.stream_file(str(resources_folder1.joinpath(str(hzid) + '.wav')))
elif hzid > 1000 and hzid < 2001:
stream = miniaudio.stream_file(str(resources_folder2.joinpath(str(hzid) + '.wav')))
elif hzid > 2000 and hzid < 3001:
stream = miniaudio.stream_file(str(resources_folder3.joinpath(str(hzid) + '.wav')))
elif hzid > 3000 and hzid < 4001:
stream = miniaudio.stream_file(str(resources_folder3.joinpath('cuo.wav')))
#大于3000为错,其余为对
elif hzid > 4000 and hzid < 5001:
stream = miniaudio.stream_file(str(resources_folder3.joinpath('dui.wav')))
elif hzid > 5000 and hzid < 6001:
#提醒来做题
stream = miniaudio.stream_file(str(resources_folder3.joinpath('zt.wav')))
elif hzid > 6000 and hzid < 7001:
stream = miniaudio.stream_file(str(resources_folder3.joinpath('zt1.wav')))
elif hzid > 7000 and hzid < 8001:
stream = miniaudio.stream_file(str(resources_folder3.joinpath('zt2.wav')))
with miniaudio.PlaybackDevice() as device:
device.start(stream)
sleep(idsc)
def bfsya(hzid,idsc):
if hzid < 1001:
stream = miniaudio.stream_file(str(resources_folder1.joinpath(str(hzid) + 'a.wav')))
elif hzid > 1000 and hzid < 2001:
stream = miniaudio.stream_file(str(resources_folder2.joinpath(str(hzid) + 'a.wav')))
elif hzid > 2000 and hzid < 3001:
stream = miniaudio.stream_file(str(resources_folder3.joinpath(str(hzid) + 'a.wav')))
with miniaudio.PlaybackDevice() as device:
device.start(stream)
sleep(idsc)
#播放声音函数,bfsya是用于播放带a的wav文件
def maxmin(xzng):
if xzng < 9:
yshen = 0
else:
yshen = 1
if xzng > 16:
globals()['rongy'] = 1
else:
globals()['rongy'] = 0
if xzng in (1,9,17):
njt = '一年级'
njt1 = '二年级上'
elif xzng in (2,10,18):
njt = '二年级'
njt1 = '三年级上'
elif xzng in (3,11,19):
njt = '三年级'
njt1 = '四年级上'
elif xzng in (4,12,20):
njt = '四年级'
njt1 = '五年级上'
elif xzng in (5,13,21):
njt = '五年级'
njt1 = '六年级上'
elif xzng in (6,14,22):
njt = '六年级'
njt1 = '五年级'
else:
njt = '二年级'
njt1 = '三年级'
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
if xzng == 15:
query_sql = "update setupme set set_gz = 16"
c.execute(query_sql)
conn.commit()
if xzng == 16:
query_sql = "update setupme set set_gz = 25"
c.execute(query_sql)
conn.commit()
#16格和25格的设置,写入setupme参数表用于下次打开
c.close()
conn.close()
return(njt,njt1,yshen)
njt,njt1,yshen = maxmin(3)
#选择年级和有声无声的函数,默认是3
def u_record(testcs,cuo_cs,yshen,cid):
#mt修改为记录是否有声的开关
if testcs > 0:
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
c.execute("UPDATE record SET ts = ?,ct = ?,mt = ? WHERE cid = ?;", (testcs,cuo_cs,yshen,cid))
conn.commit()
c.close()
conn.close()
#记录每次的题数,错题数,每题用多少秒,每个界面用一个cid
def u_cs1(duid):
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
query_sql = "update hz set cs1 = cs1 + 1 where id= ?"
c.execute(query_sql, (str(duid),))
conn.commit()
c.close()
conn.close()
def u_jfen(jf):
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
current_date = datetime.datetime.now()
formatted_date = current_date.strftime("%Y-%m-%d")
cursor = c.execute("SELECT count(*) FROM jfen WHERE rq='"+ formatted_date +"'")
row = cursor.fetchone()
if row[0] ==0:
query_sql = "INSERT INTO jfen (rq,jf) VALUES (?,?);"
c.execute(query_sql, (formatted_date,0,))
conn.commit()
query_sql = "update jfen set jf = jf + ? where rq= ?"
c.execute(query_sql, (jf,formatted_date,))
conn.commit()
else:
query_sql = "update jfen set jf = jf + ? where rq= ?"
c.execute(query_sql, (jf,formatted_date,))
conn.commit()
c.close()
conn.close()
#记录这个汉字的练习次数+1
def u_cs(addcs,duid):
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
query_sql = "update hz set cs = cs + ? where id= ?"
c.execute(query_sql, (str(addcs),str(duid),))
conn.commit()
c.close()
conn.close()
#为某个汉字加积分
def j_cs(addcs,duid):
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
query_sql = "update hz set cs = cs - ? where id= ?"
c.execute(query_sql, (str(addcs),str(duid),))
conn.commit()
c.close()
conn.close()
#为某个汉字减少积分
def tj_cs():
if globals()['testcs'] == 0:
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
query_str = 'select rq,sum(ts),sum(ct) from record group by rq order by rq desc limit 0,4;'
cursor = c.execute(query_str)
rows = cursor.fetchall()
stext3 = ""
for row in rows:
#采用去重统计点错用时较长的题
#cursor = c.execute("SELECT avg(yt) FROM record2 where cid in (select cid from record where rq ='"+ row[0] +"') and yt < 45000;")
cursor = c.execute("SELECT avg(yt),count(yt) FROM (SELECT *,rank() over (PARTITION by (hid*10000+cid) order by yt desc) as rank FROM record2 where cid in (select cid from record where rq ='"+ row[0] +"' and mt = 0) and yt < 30000 ) where rank =1;")
row1 = cursor.fetchone()
mt = row1[0]
if mt == None:
mt = 0
yzyt = row1[1]
cursor = c.execute("SELECT avg(yt) FROM (SELECT *,rank() over (PARTITION by (hid*10000+cid) order by yt desc) as rank FROM record2 where cid in (select cid from record where rq ='"+ row[0] +"' and mt > 0) and yt < 30000 ) where rank =1;")
row1 = cursor.fetchone()
ymt = row1[0]
if ymt == None:
ymt = 0
cursor = c.execute("SELECT sum(yt) FROM record2 where cid in (select cid from record where rq ='"+ row[0] +"') and yt < 45000")
row1 = cursor.fetchone()
zyt = row1[0]
if zyt == None:
zyt = 0
else:
zyt = int(zyt /1000 /60)
stext3 += "%s:做%d(%d)题,%d错,%d分钟,每题%d(%d)毫秒\n" % (row[0],row[1],yzyt,row[2],zyt,mt,ymt)
c.close()
conn.close()
globals()['tjcs'] = stext3
else:
stext3 = globals()['tjcs']
return(stext3)
#在界面的下面显示最近4天学习总题数等信息,方便家长检查孩子的学习情况
def in_record2(hid,cid,ytime):
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
query_str = 'INSERT INTO record2 (hid,cid,yt) VALUES (?,?,?);'
c.execute(query_str,(hid,cid,ytime,))
conn.commit()
c.close()
conn.close()
def get_numbers(numbers):
alen = random.randint(2,int(len(numbers)/4))
index = random.randint(0, len(numbers) - alen)
return numbers[index:index+alen]
def remove_element(items, remove_items):
for item in remove_items:
if item in items:
items.remove(item)
return items
def randshu():
return random.randint(1,9)/10
def randii(setgz):
ii1 = list(range(1,(setgz + 1)))
iig = get_numbers(ii1)
ii1 = remove_element(ii1, iig)
ri = random.randint(0,9)
if ri < 4:
random.shuffle(ii1)
else:
random.shuffle(ii1,randshu)
index = random.randint(0,len(ii1))
iic = ii1[:index]
iic.extend(iig)
iiout = iic + ii1[index:]
return iiout
#上面4个函数用于生成一个随机列表,里面有一段是连续的
def addfh(original_list):
x = 0
while x < len(original_list):
if '!' not in original_list[x]:
original_list[x] = original_list[x] + '!' + str(x)
x = x + 1
return original_list
def delfh(original_list):
x = 0
while x < len(original_list):
original_list[x] = original_list[x].split('!')[0]
x = x + 1
return original_list
#上面2个函数,为列表的各个元素中空值的加上符号和删除符号,保证排序不会变动
def set_all(njt,njt1):
globals()['testtime'] = globals()['testtime'] + 1
if globals()['rongy'] == 1:
globals()['testtime'] = 1 #听写模式时,永远重新出题
if globals()['testtime'] > 3:
globals()['testtime'] = 1 #3次后变为1,重新出题
if globals()['testtime'] > 1 and globals()['testtime'] <= 3:
oii = globals()['ii']
#print(globals()['hz'])
orderii = randii(globals()['set_gz'])
orderi = [x - 1 for x in orderii]
xi = []
i = 0
while i < len(orderii):
xi.append(orderii.index(oii[i])+1)
i = i + 1
ii = xi
hz = []
py = []
zc1 = []
zc2 = []
zc3 = []
zc4 = []
zc5 = []
hzid = []
kw = []
bs = []
idsc = []
hzid = sorted(globals()['hzid'], key=lambda x: orderi.index(globals()['hzid'].index(x)))
hz = delfh(sorted(addfh(globals()['hz']), key=lambda x: orderi.index(addfh(globals()['hz']).index(x))))
#print(hz)
py = delfh(sorted(addfh(globals()['py']), key=lambda x: orderi.index(addfh(globals()['py']).index(x))))
zc1 = delfh(sorted(addfh(globals()['zc1']), key=lambda x: orderi.index(addfh(globals()['zc1']).index(x))))
zc2 = delfh(sorted(addfh(globals()['zc2']), key=lambda x: orderi.index(addfh(globals()['zc2']).index(x))))
zc3 = delfh(sorted(addfh(globals()['zc3']), key=lambda x: orderi.index(addfh(globals()['zc3']).index(x))))
zc4 = delfh(sorted(addfh(globals()['zc4']), key=lambda x: orderi.index(addfh(globals()['zc4']).index(x))))
zc5 = delfh(sorted(addfh(globals()['zc5']), key=lambda x: orderi.index(addfh(globals()['zc5']).index(x))))
kw = delfh(sorted(addfh(globals()['kw']), key=lambda x: orderi.index(addfh(globals()['kw']).index(x))))
bs = delfh(sorted(addfh(globals()['bs']), key=lambda x: orderi.index(addfh(globals()['bs']).index(x))))
idsc = sorted(globals()['idsc'], key=lambda x: orderi.index(globals()['idsc'].index(x)))
globals()['ii'],globals()['hzid'],globals()['hz'],globals()['py'],globals()['zc1'],globals()['zc2'] = [],[],[],[],[],[]
globals()['zc3'],globals()['zc4'],globals()['zc5'],globals()['kw'],globals()['bs'],globals()['idsc'] = [],[],[],[],[],[]
else:
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
cursor = c.execute("SELECT round(avg(cs)) from hz where nj like '%" + njt + "%' or nj like '%" + njt1 + "%';")
row = cursor.fetchone()
csavg = row[0]
randomi = random.randint(0, 2)
if njt == '一年级':
nj = 1
elif njt == '二年级':
nj = 2
elif njt == '三年级':
nj = 3
elif njt == '四年级':
nj = 4
elif njt == '五年级':
nj = 5
else:
nj = 6
if globals()['rongy'] == 1:
cursor1 = c.execute("select count(*) from hz where nj like '%" + njt + "%' or nj like '%" + njt1 + "%'")
row1 = cursor1.fetchone()
njcount = row1[0]
cursor1 = c.execute('select count(*) from tx where nj = ?;',(nj,))
row1 = cursor1.fetchone()
txcount = row1[0]
if txcount == 0:
maxtimes = 1
else:
cursor1 = c.execute('select max(times) from tx where nj = ?;',(nj,))
row1 = cursor1.fetchone()
maxtimes = row1[0]
cursor1 = c.execute('select count(*) from tx where nj = ? and times = ?;',(nj,maxtimes,))
row1 = cursor1.fetchone()
nowtxcount = row1[0]
#nowtxcount为本轮听写的所有的字
if njcount - nowtxcount < 25:
maxtimes = maxtimes + 1
#上面为确定maxtimes
cursor = c.execute("SELECT id, hz, py, zc1, zc2, zc3, zc4, zc5, kw, bs, sc from hz where (nj like '%" + njt + "%' or nj like '%" + njt1 + "%') and id not in (select hid from tx where nj = " + str(nj) + " and times = " + str(maxtimes) + ") ORDER BY RANDOM() LIMIT " + str(globals()['set_gz']))
rows = cursor.fetchall()
for row in rows:
c.execute('insert into tx (nj,hid,cid,times) values (?,?,?,?);',(nj,row[0],globals()['cid'],maxtimes,))
conn.commit()
#三种难度,1是按积分最小的练习,2是按积分在平均值以内的练习,3是随机练习
else:
if randomi == 0:
globals()['kn'] = 3
cursor = c.execute("SELECT id, hz, py, zc1, zc2, zc3, zc4, zc5, kw, bs, sc from hz where nj like '%" + njt + "%' or nj like '%" + njt1 + "%' order by cs asc limit 0," + str(globals()['set_gz']))
rows = cursor.fetchall()
elif randomi == 1:
globals()['kn'] = 2
cursor = c.execute("SELECT id, hz, py, zc1, zc2, zc3, zc4, zc5, kw, bs, sc from hz where (nj like '%" + njt + "%' or nj like '%" + njt1 + "%') and cs <= " + str(csavg) + " ORDER BY RANDOM() LIMIT " + str(globals()['set_gz']))
rows = cursor.fetchall()
else:
globals()['kn'] = 1
cursor = c.execute("SELECT id, hz, py, zc1, zc2, zc3, zc4, zc5, kw, bs, sc from hz where nj like '%" + njt + "%' or nj like '%" + njt1 + "%' ORDER BY RANDOM() LIMIT " + str(globals()['set_gz']))
rows = cursor.fetchall()
hz = []
py = []
zc1 = []
zc2 = []
zc3 = []
zc4 = []
zc5 = []
hzid = []
kw = []
bs = []
idsc = []
i = 1
for row in rows:
if i < (globals()['set_gz'] + 1):
hzid.append(row[0])
hz.append(row[1])
py.append(row[2])
zc1.append(str(row[3]))
zc2.append(str(row[4]))
zc3.append(str(row[5]))
zc4.append(str(row[6]))
zc5.append(str(row[7]))
kw.append(row[8])
bs.append(row[9])
idsc.append(row[10])
i = i + 1
#只有听写时,列表按顺序排列
if globals()['rongy'] == 1:
ii = list(range(1,(globals()['set_gz'] + 1)))
else:
ii = randii(globals()['set_gz'])
c.close()
conn.close()
return ii,hzid,hz,py,zc1,zc2,zc3,zc4,zc5,kw,bs,idsc
#按年级返回16/25个汉字的拼音组词、课文、id、答题次数和音频文件的播放长度
def is_integer(s):
try:
int(s)
return True
except ValueError:
return False
def hello():
#msg="现在时间是:"+datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')+",第一次提醒你"
#print(msg)
play_sound_background(5500,3.432)
def hello1():
play_sound_background(6500,3.623)
#msg="现在时间是:"+datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')+",第二次提醒你"
#print(msg)
def hello2():
play_sound_background(7500,4.113)
#msg="现在时间是:"+datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')+",第三次提醒你"
#print(msg)
globals()['ttt'] = 0
names['t_' + str(globals()['ttt'])] = Timer(30, hello)
names['t_' + str(globals()['ttt'])].setDaemon(True)
names['t_' + str(globals()['ttt'])].start()
names['t1_' + str(globals()['ttt'])] = Timer(60, hello1)
names['t1_' + str(globals()['ttt'])].setDaemon(True)
names['t1_' + str(globals()['ttt'])].start()
names['t2_' + str(globals()['ttt'])] = Timer(90, hello2)
names['t2_' + str(globals()['ttt'])].setDaemon(True)
names['t2_' + str(globals()['ttt'])].start()
def build(app):
# 定义组件
c_box = toga.Box()
b1_box = toga.Box()
b2_box = toga.Box()
b3_box = toga.Box()
b4_box = toga.Box()
if globals()['set_gz'] == 25:
b5_box = toga.Box()
box = toga.Box()
abox = toga.Box()
bigbox = toga.Box()
image = toga.Image(str(giffolder.joinpath(str(random.randint(1, 2791))+'.gif')))
imageview = toga.ImageView(image=image,style=Pack(width=100, height=100, padding=8))
c_input = toga.TextInput(readonly=True,style=Pack(font_size=22))
c_label = toga.Label("请选择几年级,(有声),还可以选择16或25格为下次模式", style=Pack(text_align=LEFT))
c_label1 = toga.Label("", style=Pack(text_align=LEFT, font_size=12))
c_label2 = toga.Label("", style=Pack(text_align=LEFT))
c_label3 = toga.Label("", style=Pack(text_align=LEFT))
#界面设置
def bt1(bb, widget):
#msg="现在时间是:"+datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')+",做题时间!"
#print(msg)
names['t_' + str(globals()['ttt'])].cancel()
names['t1_' + str(globals()['ttt'])].cancel()
names['t2_' + str(globals()['ttt'])].cancel()
globals()['ttt'] = globals()['ttt'] + 1
if globals()['ttt'] >= 60:
globals()['ttt'] = 0
names['t_' + str(globals()['ttt'])] = Timer(30, hello)
names['t_' + str(globals()['ttt'])].setDaemon(True)
names['t_' + str(globals()['ttt'])].start()
names['t1_' + str(globals()['ttt'])] = Timer(60, hello1)
names['t1_' + str(globals()['ttt'])].setDaemon(True)
names['t1_' + str(globals()['ttt'])].start()
names['t2_' + str(globals()['ttt'])] = Timer(90, hello2)
names['t2_' + str(globals()['ttt'])].setDaemon(True)
names['t2_' + str(globals()['ttt'])].start()
if is_integer(bb):
xzng = int(bb)
else:
xzng = bb
globals()['testcs'] += 1
globals()['etime'] = time()
globals()['ytime'] = int(etime - stime)
yytime = int((etime - stime)*1000)
if duid > 0 and cid > 0 and rid > 0 and globals()['rongy'] != 1:
in_record2(duid,cid,yytime)
#记录用时
if rid == 0:
current_date = datetime.datetime.now()
formatted_date = current_date.strftime("%Y-%m-%d")
formatted_time = current_date.strftime("%H:%M:%S")
#每次rid=0时,生成一个记录,记录学习情况
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
c.execute("INSERT INTO record (rq,sj,ts,ct,mt) VALUES (?,?,?,?,?);", (formatted_date,formatted_time,0,0,0))
conn.commit()
cursor = c.execute("SELECT sum(jf) from jfen")
row = cursor.fetchone()
globals()['zjf'] = row[0]
#获取总积分
cursor = c.execute("SELECT jf from jfen order by jid desc limit 0,1")
row = cursor.fetchone()
globals()['jtjf'] = row[0]
#获取今日积分
cursor = c.execute("SELECT cid from record order by cid desc")
row = cursor.fetchone()
c.close()
conn.close()
globals()['cid'] = row[0]
#提取cid到全局变量中
globals()['testcs'] = 0
#rid为0时,测试次数重计
globals()['cuo_cs'] = 0
#错误次数也重计
globals()['begintime'] = time()
#设定rid为0是的开始时间,可以计算做完16个汉字的时间
globals()['njt'],globals()['njt1'],globals()['yshen'] = maxmin(xzng)
#将年级和有声的变量按选择存入到全局变量
globals()['ii'],globals()['hzid'],globals()['hz'],globals()['py'],globals()['zc1'],globals()['zc2'],globals()['zc3'],globals()['zc4'],globals()['zc5'],globals()['kw'],globals()['bs'],globals()['idsc']=set_all(globals()['njt'],globals()['njt1'])
#将全部要用到的变量存入全局变量
globals()['stime'] = time()
#设定本次开始时间
for i in range(1,(globals()['set_gz'] + 1)):
if globals()['rongy'] != 1:
setattr(names['button_' + str(i)],"text",hz[ii[i-1]-1])
else:
setattr(names['button_' + str(i)],"text",str(i)) #听写时不显示汉字,显示数字
setattr(names['button_' + str(i)],"on_press",partial(bt1, hz[ii[i-1]-1]))
#设置按键名称,即把汉字显示在按钮上,汉字通过随机错排列,这个ii就是打乱了的1到16顺序,2个-1是因为最小是0
globals()['rid'] = 1
#rid变为1,算第一次,答对了rid才会增加1
globals()['duid'] = hzid[rid-1]
#这个是对的汉字在数据库中的汉字
globals()['jj'] = hz[rid-1]
#这个变量是记忆对的汉字选择的按钮的编码,index是寻址,寻找rid在ii列中的位置,这个位置+1为按钮的参数
if yshen == 0:
if zc2[rid-1] == '':
c_value = py[rid-1] + " " + zc1[rid-1].replace(hz[rid-1],'□')
else:
zc = []
zc.append(zc1[rid-1])
zc.append(zc2[rid-1])
if globals()['testtime'] == 1:#第一次显示拼音加2个组词
c_value = py[rid-1] + " " + zc1[rid-1].replace(hz[rid-1],'□') + "、" + zc2[rid-1].replace(hz[rid-1],'□')
elif globals()['testtime'] == 2:#第二次显示部首加1组词
c_value = py[rid-1] + " [" + bs[rid-1] + "] " + zc1[rid-1].replace(hz[rid-1],'□')
else:
c_value = "部首[" + bs[rid-1] + "] " + zc1[rid-1].replace(hz[rid-1],'□') + "、" + zc2[rid-1].replace(hz[rid-1],'□')
if zc3[rid-1] != '':
zc.append(zc3[rid-1])
if zc4[rid-1] != '':
zc.append(zc4[rid-1])
if zc5[rid-1] != '':
zc.append(zc5[rid-1])
zc = random.sample(zc,2)
if globals()['testtime'] == 1:#第一次显示拼音加2个组词
c_value = py[rid-1] + " " + zc[0].replace(hz[rid-1], '□')+ "、" + zc[1].replace(hz[rid-1],'□')
elif globals()['testtime'] == 2:#第二次显示拼音加1个组词
c_value = py[rid-1] + " [" + bs[rid-1] + "] " + zc[0].replace(hz[rid-1], '□')
else:#第三次不显示拼音,显示2个组词
c_value = "部首[" + bs[rid-1] + "] " + zc[0].replace(hz[rid-1], '□')+ "、" + zc[1].replace(hz[rid-1],'□')
#无声是在输入栏显示拼音和隐去本字的组词,这里面采用随机数,在多个组词中随机选择2个
c_text = '来自:' + kw[rid-1]
#显示来自年级和课文
c_label.text = c_text
c_label3.text = tj_cs()
#rid为0是,显示统计的4天学习情况
if yshen == 0:
c_input.value = c_value
else:
if zc4[rid-1] != '' and random.randint(0,1) == 0:
play_sound_backgrounda(hzid[rid-1],idsc[rid-1])
else:
play_sound_background(hzid[rid-1],idsc[rid-1])
#当选择有声时,用miniaudio发出声音,不使用sleep就不会播放声音,sleep的时长就是播放声音的时长,后台播放,虽然会重音但比较流畅
#rid为0为一开始设置第一题
else:
text5 = ""
if rid >=1:
text5 = text5 + hz[rid-1] + "(" + py[rid-1] + ") " + zc1[rid-1] + " " + zc2[rid-1] + " " + zc3[rid-1] + " " + zc4[rid-1] + " " + zc5[rid-1]
#text5是复习内容
if testcs > 0:
stext = '%d秒,共答%d题,错%d题,每题%d秒。' % (int(etime-begintime),testcs,cuo_cs,int((etime-begintime) / testcs))
if xzng == globals()['jj']:
if globals()['rongy'] == 1:
setattr(names['button_' + str(ii[rid-1])],"text",hz[rid-1])
c_label1.text = "复习:" + text5
abox.clear()
image = toga.Image(str(giffolder.joinpath(str(hzid[rid-1]) + '.gif')))
imageview = toga.ImageView(image=image,style=Pack(width=100, height=100, padding=10))
abox.add(imageview)
#回答正确才显示复习内容
if yshen == 1:
c_input.value = hz[rid-1] + " [" + bs[rid-1] + "]√ (" + py[rid-1] + ") " + zc1[rid-1] + " " + zc2[rid-1] + " " + zc3[rid-1]
c_label2.text = '本轮学习' + stext
else:
c_label2.text = '答对。本轮' + stext
jf1 = kn + 6
#原如果答题次数小于100,按100-次数后除以10取整为增加积分,取消直接加6分
if yshen ==1:
jf1 = jf1 - 1
else:
jf1 = jf1 + 2
#无声模式积分加2分,有声减1分
if globals()['set_gz'] == 25:
jf1 = jf1 + 2
#25格再加2分
jf1 = jf1 - (globals()['testtime'] - 1) * 2 #积分减去测试次数*2,即第二次-2分,第三次-4分
if globals()['rongy'] != 1:
if ytime <= 3:
u_cs(4,hzid[rid-1])
jfen = jf1 + 4
u_jfen(jfen)
#用时小于3秒加4分
elif ytime > 3 and ytime <= 4:
u_cs(3,hzid[rid-1])
jfen = jf1 + 3
u_jfen(jfen)
#用时小于4秒加3分
elif ytime > 4 and ytime <= 5:
u_cs(2,hzid[rid-1])
jfen = jf1 + 2
u_jfen(jfen)
#用时小于5秒加2分
else:
u_cs(1,hzid[rid-1])
jfen = jf1 + 1
u_jfen(jfen)
#用时大于5秒加1分
#play_sound_background(3500,1.174) 播放正确的声音
globals()['stime'] = time()
globals()['rid'] += 1
#回答正确,开始下一个汉字的计时和rid
if rid == (globals()['set_gz'] + 1):
if yshen != 0:
play_sound_background(4500,1.174)
sleep(1.1)
#切换16个字界面时,播放答对了,让孩子知道过篇了
u_record(testcs,cuo_cs,yshen,cid)
current_date = datetime.datetime.now()
formatted_date = current_date.strftime("%Y-%m-%d")
formatted_time = current_date.strftime("%H:%M:%S")
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
c.execute("INSERT INTO record (rq,sj,ts,ct,mt) VALUES (?,?,?,?,?);", (formatted_date,formatted_time,0,0,0))
conn.commit()
cursor = c.execute("SELECT sum(jf) from jfen")
row = cursor.fetchone()
globals()['zjf'] = row[0]
cursor = c.execute("SELECT jf from jfen where rq = '" + formatted_date + "' limit 0,1")
row = cursor.fetchone()
globals()['jtjf'] = row[0]
cursor = c.execute("SELECT cid from record order by cid desc")
row = cursor.fetchone()
globals()['cid'] = row[0]
c.close()
conn.close()
globals()['testcs'] = 0
globals()['cuo_cs'] = 0
globals()['begintime'] = time()
njt = globals()['njt']
globals()['ii'],globals()['hzid'],globals()['hz'],globals()['py'],globals()['zc1'],globals()['zc2'],globals()['zc3'],globals()['zc4'],globals()['zc5'],globals()['kw'],globals()['bs'],globals()['idsc']=set_all(njt,globals()['njt1'])
globals()['stime'] = time()
for i in range(1,(globals()['set_gz'] + 1)):
if globals()['rongy'] != 1:
setattr(names['button_' + str(i)],"text",hz[ii[i-1]-1])
else:
setattr(names['button_' + str(i)],"text",str(i)) #听写时不显示汉字,显示数字
setattr(names['button_' + str(i)],"on_press",partial(bt1, hz[ii[i-1]-1]))
globals()['rid'] = 1
#当rid等于17是,实际就是第二轮开始,初始化一些变量,重新写入cid
globals()['duid'] = hzid[rid-1]
globals()['jj'] = hz[rid-1]
#因为上面rid加1了,所以这2个全局变量都要变。
if yshen == 0:
if zc2[rid-1] == '':
c_value = py[rid-1] + " " + zc1[rid-1].replace(hz[rid-1],'□')
else:
zc = []
zc.append(zc1[rid-1])
zc.append(zc2[rid-1])
if globals()['testtime'] == 1:#第一次显示拼音加2个组词
c_value = py[rid-1] + " " + zc1[rid-1].replace(hz[rid-1],'□') + "、" + zc2[rid-1].replace(hz[rid-1],'□')
elif globals()['testtime'] == 2:
c_value = py[rid-1] + " [" + bs[rid-1] + "] " + zc1[rid-1].replace(hz[rid-1],'□')
else:
c_value = "部首[" + bs[rid-1] + "] " + zc1[rid-1].replace(hz[rid-1],'□') + "、" + zc2[rid-1].replace(hz[rid-1],'□')
if zc3[rid-1] != '':
zc.append(zc3[rid-1])
if zc4[rid-1] != '':
zc.append(zc4[rid-1])
if zc5[rid-1] != '':
zc.append(zc5[rid-1])
zc = random.sample(zc,2)
if globals()['testtime'] == 1:#第一次显示拼音加2个组词
c_value = py[rid-1] + " " + zc[0].replace(hz[rid-1], '□')+ "、" + zc[1].replace(hz[rid-1],'□')
elif globals()['testtime'] == 2:#第二次显示拼音加1个组词
c_value = py[rid-1] + " [" + bs[rid-1] + "] " + zc[0].replace(hz[rid-1], '□')
else:#第三次显示拼音,显示2个组词
c_value = "部首[" + bs[rid-1] + "] " +zc[0].replace(hz[rid-1], '□')+ "、" + zc[1].replace(hz[rid-1],'□')
if yshen == 0:
c_input.value = c_value
else:
if zc4[rid-1] != '' and random.randint(0,1) == 0:
play_sound_backgrounda(hzid[rid-1],idsc[rid-1])
else:
play_sound_background(hzid[rid-1],idsc[rid-1])
#上面为选择正确时的程序
else:
globals()['cuo_cs'] += 1
if globals()['rongy'] == 1:
setattr(names['button_' + str(ii[rid-1])],"text",hz[rid-1])
c_label1.text = "提示:" + text5
if yshen == 1:
c_input.value = "答错了!请重新选择!"
c_label2.text = '累计学习' + stext
play_sound_background(3500,1.325)
sleep(1.2)
#播放错误的声音,还是需要sleep,不然不会停下来
if zc4[rid-1] != '' and random.randint(0,1) == 0:
play_sound_backgrounda(hzid[rid-1],idsc[rid-1])
else:
play_sound_background(hzid[rid-1],idsc[rid-1])
#选择错误时的程序,重新读一遍
else:
if zc2[rid-1] == '':
c_value = py[rid-1] + " [" + bs[rid-1] + "] " + zc1[rid-1].replace(hz[rid-1],'□')
else:
zc = []
zc.append(zc1[rid-1])
zc.append(zc2[rid-1])
c_value = py[rid-1] + " [" + bs[rid-1] + "] " + zc1[rid-1].replace(hz[rid-1],'□') + "、" + zc2[rid-1].replace(hz[rid-1],'□')
if zc3[rid-1] != '':
zc.append(zc3[rid-1])
if zc4[rid-1] != '':
zc.append(zc4[rid-1])
if zc5[rid-1] != '':
zc.append(zc5[rid-1])
zc = random.sample(zc,2)
c_value = py[rid-1] + " [" + bs[rid-1] + "] " + zc[0].replace(hz[rid-1], '□')+ "、" + zc[1].replace(hz[rid-1],'□')
c_input.value = "重答:" + c_value
c_label2.text = '答错!累计' + stext
if globals()['rongy'] != 1:
j_cs(5,hzid[rid-1])
jfen = -6
u_jfen(jfen)
#选择错误,扣6分
globals()['stime'] = time()
if globals()['rongy'] != 1:
if jfen > 0:
c_text = '总分:' + str(zjf) + ',今日:' + str(jtjf) + ',本题获得' + str(jfen) +'分。来自:' + kw[rid-1]
else:
c_text = '总分:' + str(zjf) + ',今日:' + str(jtjf) + ',本题扣' + str(abs(jfen)) +'分。来自:' + kw[rid-1]
else:
c_text = '总分:' + str(zjf) + ',今日:' + str(jtjf) + ',来自:' + kw[rid-1]
c_label.text = c_text
c_label3.text = tj_cs()
if globals()['cid'] > 0:
u_record(testcs,cuo_cs,yshen,cid)
u_cs1(hzid[rid-1])
#记录学习情况
if globals()['set_gz'] == 16:
aaa = '一 二 三 四 五 六 无 声 ㈠ ㈡ ㈢ ㈣ ㈤ ㈥ 16 25'.split()
for i in range(1,17):
names['button_' + str(i)] = toga.Button(aaa[i-1], on_press=partial(bt1, str(i)),style=Pack(font_size=28))
else:
aaa = '一 二 三 四 五 六 无 声 ㈠ ㈡ ㈢ ㈣ ㈤ ㈥ 16 25 ㈠ ㈡ ㈢ ㈣ ㈤ ㈥ 听 写 用'.split()
for i in range(1,26):
names['button_' + str(i)] = toga.Button(aaa[i-1], on_press=partial(bt1,str(i)),style=Pack(font_size=25))
#用set_g参数控制16格和25格的初始界面
# 设置组件样式和布局
c_box.add(c_input)
box.add(c_box)
if globals()['set_gz'] == 16:
for i in range(1,5):
b1_box.add(names['button_' + str(i)])
for i in range(5,9):
b2_box.add(names['button_' + str(i)])
for i in range(9,13):
b3_box.add(names['button_' + str(i)])
for i in range(13,17):
b4_box.add(names['button_' + str(i)])
else:
for i in range(1,6):
b1_box.add(names['button_' + str(i)])
for i in range(6,11):
b2_box.add(names['button_' + str(i)])
for i in range(11,16):
b3_box.add(names['button_' + str(i)])
for i in range(16,21):
b4_box.add(names['button_' + str(i)])
for i in range(21,26):
b5_box.add(names['button_' + str(i)])
abox.add(imageview)
box.add(b1_box)
box.add(b2_box)
box.add(b3_box)
box.add(b4_box)
if globals()['set_gz'] == 25:
box.add(b5_box)
box.add(c_label)
box.add(c_label1)
box.add(c_label2)
box.add(c_label3)
bigbox.add(box)
bigbox.add(abox)
# 设置 outer box 和 inner box 的样式
box.style.update(direction=COLUMN, padding=4)
abox.style.update(direction=COLUMN, padding=1)
bigbox.style.update(direction=ROW, padding=1)
b1_box.style.update(direction=ROW, padding=1)
b2_box.style.update(direction=ROW, padding=1)
b3_box.style.update(direction=ROW, padding=1)
b4_box.style.update(direction=ROW, padding=1)
if globals()['set_gz'] == 25:
b5_box.style.update(direction=ROW, padding=1)
c_box.style.update(direction=ROW, padding=5)
# 设置单个组件的样式
c_input.style.update(width=345, flex=1)
# button.style.update(padding=15)
c_label.style.update(width=345, padding_left=4)
c_label1.style.update(width=345, padding_left=4)
c_label2.style.update(width=345, padding_left=4)
c_label3.style.update(width=345, padding_left=4)
if globals()['set_gz'] == 16:
for i in range(1,17):
names['button_' + str(i)].style.update(width=85, height=85, padding=1, background_color='white')
else:
for i in range(1,26):
names['button_' + str(i)].style.update(width=68, height=68, padding=1, background_color='white')
return bigbox
def play_sound_background(hzid,idsc):
thread = threading.Thread(target=bfsy, args=(hzid,idsc,))
thread.daemon = True
thread.start()
def play_sound_backgrounda(hzid,idsc):
thread = threading.Thread(target=bfsya, args=(hzid,idsc,))
thread.daemon = True
thread.start()
#用线程,在后台播放声音
def main():
return toga.App(globals()['app_name'], "org.qwrz2", startup=build)
if __name__ == "__main__":
main().main_loop()
附注:用beeware生成安卓app时,gif动画不能正常显示,这个问题待解决;另外用60个线程来提醒做题的做法我自己觉得很low。
附上win版安装程序,如果感兴趣可以与我索要安卓app。