前段时间遗留了一个问题:千纬认字(更新增加部首及笔顺动画)程序源码及win版发布-CSDN博客
解决过程:
1.我想去toga里面有个显示网页的WebView,直接在webview的url加上本地gif图片地址,发现提示错误"WebView can only display http:// and https:// URLs",只能显示网络上的网页;
2.(无用功)为此我继续采集www.cidianso.com网站上的gif的url,再用WebView显示,发现我要显示100*100的gif,在电脑上是正常的,但在手机上gif按原图像300*300显示,不会缩放。
3.为此,我继续上网查找办法,发现webview.py中有set_content函数,看说明是可以设置html内容的。再找发现https://github.com/beeware/toga/issues/2242中,有个办法可以使用。这样在gif标签中设置高度和宽度就解决这个问题。
4.但是,我这个app是做给小孩学习的,一开始考虑是可以脱网使用,同时频繁访问www.cidianso.com网站也不是个好办法。偶然想起可以用base64的图片格式。
5.为此,查找相关例子,修改代码,让其实现base64图片功能,终于大功告成,解决在Toga显示gif动画的功能,当然,这个过程是漫长的,有段时间还考虑用pillow逐帐显示图片,但都以失败告终。显示笔顺动画有利于小孩子按笔顺写好字。
上源代码:
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
import base64
#导入必要的库,其中这个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 = 2
if sjcs == 1:
sj_file = '/data/data/com.qwrz.qwrz2/qwrz0605.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/文件夹中,不用获取权限,减少麻烦,我以前的版本是放在文档中方便分析数据
global duihz, duipy, duizc1, duizc2, duizc3,duizc4,duizc5, duid, kw, jj
global stime, etime, ytime, begintime, testcs, cuo_cs, yshen, cid, tjcs
#上面2行好像可以删除
names = globals()
cid = 0 #每次记录id
yshen = 0 #有声无声
rongy = 0 #实际是用于听写,不是容易,0为非听写模式
testtime = 0 #用于记录测试次数,每16-25个字测试3次
testcs = 0 #测试次数
cuo_cs = 0 #错题次数
stime = time()
begintime = time() #开始时间
rid = 0 #每界面的一个id
cuot = 0
duid = 0
jf = 0 #积分
kn = 0 #难度
jj = '' #记录正确的字
zjf = 0 #总积分
prehzid = 0 #前一个字的id
preidsc = 0 #前一个字的播放时长
global njt,njt1
njt = '一年级'
#上面是全局参数和默认值
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()
#在积分表中写入今天的一行,用于记录今天的积分
def bfsy(hzid,idsc):
if globals()['prehzid'] > 0 and globals()['preidsc'] > 0 and globals()['rongy'] ==1:
if prehzid < 1001:
stream = miniaudio.stream_file(str(resources_folder1.joinpath(str(prehzid) + '.wav')))
elif prehzid > 1000 and prehzid < 2001:
stream = miniaudio.stream_file(str(resources_folder2.joinpath(str(prehzid) + '.wav')))
elif prehzid > 2000 and prehzid < 3001:
stream = miniaudio.stream_file(str(resources_folder3.joinpath(str(prehzid) + '.wav')))
with miniaudio.PlaybackDevice() as device:
device.start(stream)
sleep(preidsc + 0.5)
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 globals()['prehzid'] > 0 and globals()['preidsc'] > 0 and globals()['rongy'] ==1:
if prehzid < 1001:
stream = miniaudio.stream_file(str(resources_folder1.joinpath(str(prehzid) + '.wav')))
elif prehzid > 1000 and prehzid < 2001:
stream = miniaudio.stream_file(str(resources_folder2.joinpath(str(prehzid) + '.wav')))
elif prehzid > 2000 and prehzid < 3001:
stream = miniaudio.stream_file(str(resources_folder3.joinpath(str(prehzid) + '.wav')))
with miniaudio.PlaybackDevice() as device:
device.start(stream)
sleep(preidsc + 0.5)
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 getgifurl(hzid):
# gifurl = 'https://www.cidianso.com/UploadFile/zi/65163692.gif'
# if hzid > 0 and hzid <= 2791:
# conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
# c = conn.cursor()
# cursor = c.execute("SELECT gifurl FROM hz WHERE id=?;",(hzid,))
# row = cursor.fetchone()
# gifurl = 'https://www.cidianso.com' + row[0]
# c.close()
# conn.close()
##gifurl = 'file:///' + str(giffolder.joinpath(str(hzid)+'.gif')) 失败也不能显示本地文件
with open(str(giffolder.joinpath(str(hzid)+'.gif')), 'rb') as file:
img_data = file.read()
encoded_data = base64.b64encode(img_data)
return encoded_data.decode('utf-8')
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 u_tx(duid):
if globals()['cid']>0:
conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)
c = conn.cursor()
query_sql = "update tx set nj = nj - 10 where hid= ? and cid = ? and nj > 10;"
c.execute(query_sql, (duid,globals()['cid'],))
conn.commit()
c.close()
conn.close()
#听写时,hid减10000,用于记忆听写过的字
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,插入tx表,首先加10000,后再每个减10000,这样保证有听写过的字就能避免再听写
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+10,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():
play_sound_background(5500,3.432)
def hello1():
play_sound_background(6500,3.623)
def hello2():
play_sound_background(7500,4.113)
globals()['ttt'] = 0
if globals()['rongy'] != 1 and globals()['rid'] > 0:
names['t_' + str(globals()['ttt'])] = Timer(30, hello)
names['t_' + str(globals()['ttt'])].setDaemon(True)
names['t_' + str(globals()['ttt'])].start()
#听写模式1分钟才提醒
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()
webview = toga.WebView(style=Pack(width=120, height=120,padding_left=5))
# html = '<img src="' + getgifurl(random.randint(1, 2791)) + '" width="100" height="100" />'
html = f"<img src='data:image/gif;base64,{getgifurl(random.randint(1, 2791))}' width='100' height='100' />"
webview.set_content("data:text/html", html)
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):
if 't_' + str(globals()['ttt']) in names:
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
if globals()['rongy'] != 1:
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])
if globals()['rongy'] == 1:
u_tx(hzid[rid-1]) #有念声音的地方加上这个函数,用于在听写表减掉10000
globals()['prehzid'] = hzid[rid-1]
globals()['preidsc'] = 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()
#webview = toga.WebView(style=Pack(width=120, height=120,padding_left=5))
#html = '<img src="' + getgifurl(hzid[rid-1]) + '" width="100" height="100" />'
html = f"<img src='data:image/gif;base64,{getgifurl(hzid[rid-1])}' width='100' height='100' />"
webview.set_content("data:text/html", html)
#abox.add(webview)
#回答正确才显示复习内容
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])
if globals()['rongy'] == 1:
u_tx(hzid[rid-1]) #有念声音的地方加上这个函数,用于在听写表减掉10000,错就不用
globals()['prehzid'] = hzid[rid-1]
globals()['preidsc'] = 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(webview)
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()
app下载链接等我评论来发。