美文网首页
tkinter实践之:写一个测验英语的.exe程序

tkinter实践之:写一个测验英语的.exe程序

作者: fakeProgramer | 来源:发表于2023-02-17 22:23 被阅读0次
    笔者最近在学英语(天道好轮回,终于意识到了学英语的重要性),想写一个小工具把学习中遇到的生词、句子记录下来,能够实现中英抽验,并统计历史作答的成绩。虽然市面上有更成熟的单词类app,但自己写一个当练手也好。

    【功能】

    1、词句录入,删除;
    2、词句抽验;
    3、成绩统计;
    4、一键初始化。

    【拆分】

    主界面。

    包括词句录入、开始测试两个功能按钮;展示成绩统计;展示共有多少个词、句。

    子界面-词句录入。

    主界面触发,弹窗二级界面。包含两个文本框给用户输入英文和中文,提交前验证是否已存在,验证通过后保存。

    子界面-抽验。

    主界面触发,弹窗二级界面。包含一个Label标签,用于显示题目,一个Entry框用于用户作答。主界面选择不同功能,Label标签显示内容不同,以实现词句的中英文互考翻译。实时统计本次的作答结果并显示,点击“退出”将本次成绩和历史成绩合并。

    一键初始化。

    数据需要操作本地文件的读写,所以一键生成初始化json(保存词句)、ini文件(保存成绩);同时一键清空系统数据。


    【语言/模块】

    python,tkinter,json,os,random


    代码实现


    【主界面】

    定义两个Button,回调录入函数;

    • 单词录入;
    • 句子录入;

    w = tk.Tk()
    w.title('快乐背单词')
    tk.Label(w, text='开始测试吧!').grid(row=1, column=0)
    tk.Button(w, text='单词录入', bg='gray', command=lambda :ui_record_page(choice='words')).grid(row=3, column=3)
    

    定义两个Label显示词库数量(程序启动即读取词库数量):

    • 目前系统有多少单词;
    • 目前系统有多少句子;

    tk.Label(w, text=wordnum).grid(row=2,column=0)
    tk.Label(w, text=sentencenum).grid(row=2, column=1)
    

    定义四个Button,回调抽验函数;

    • 单词中考英;
    • 单词英考中;
    • 句子中考英;
    • 句子英考中;

    tk.Button(w, text='出英文单词', bg='pink', command=lambda :ui_test_page(choice='enword')).grid(row=3,column=0)
    tk.Button(w, text='出中文单词', bg='yellow', command=lambda :ui_test_page(choice='cnword')).grid(row=3, column=1)
    tk.Button(w, text='出英文句子', bg='pink', command=lambda :ui_test_page(choice='ensentence')).grid(row=4, column=0)
    tk.Button(w, text='出中文句子', bg='yellow', command=lambda :ui_test_page(choice='cnsentence')).grid(row=4, column=1)
    

    定义两个Label分别显示单词和句子的作答统计(程序启动即读历史成绩):

    • 共答过m个单词,累计正确率n%;
    • 共答过q个句子,累计正确率p%;

    tk.Label(w, text=words).grid(row=6, column=0, columnspan=4)
    tk.Label(w, text=sentences).grid(row=7, column=0, columnspan=4)
    

    【子界面:录入词句】

    将词、句以字典的形式分别保存进word.json、sentence.json。{'key': '值'},根据用户在主界面的不同选择,回调函数时携带一个参数,告诉函数读写哪个json文件。参数如下:

    • ‘words’,读写word.json;
    • ‘sentences’,读写sentence.json;

    if choice == 'words':
        filename = './happylearningini/words.json'
    else:
        filename = './happylearningini/sentences.json'
    with open (filename, mode='r',encoding='utf-8') as f:
        try:
            datas = json.load(f)
        except:
            datas = {}
    if enText.get('1.0', tk.END).strip() in datas.keys():
        tk.messagebox.showinfo(title='警告', message='单词或句子已存在。')
    else:
        with open(filename, mode='w', encoding='utf-8') as f:
            datas[enText.get('1.0', tk.END).strip()] = cnText.get('1.0', tk.END).strip()
            json.dump(datas, f)
            enText.delete('1.0', tk.END)
            cnText.delete('1.0', tk.END)
            tk.messagebox.showinfo(title='提醒', message='保存成功。')
    

    定义两个Entry,让用户输入英文和中文;

    englishText = tk.Text(w, height=5, width=50)
    chineseText = tk.Text(w, height=5, width=50)
    

    定义一个Button,回调submit功能读取json文件;函数校验英文key是否存在,是则弹窗提醒,否则保存。


    tk.Button(w, text=f'保存{types}',command=lambda :\
        save_record(choice=choice,enText=englishText, cnText=chineseText)).grid(row=4, column=1)
    

    【子界面:抽验】
    定义一个Entry和Text,分别用于展示题目和接收用户的输入(这里展示题目可以用Label标签,但测试发现子界面的StringVar对象无法实时更新,有兴趣的可以自行试试用StringVar写);


    qEntry = tk.Entry(w1)
    answerText = tk.Text(w1, height=5, width=50)
    

    根据用户在主界面的不同选择,回调抽验函数时携带一个参数,告诉函数往题目Entry里放什么内容。参数如下:

    • ‘enwords’,单词英考中,读取word.json并将key放入题目Entry;
    • ‘cnwords’,单词中考英,读取word.json并将value放入题目Entry;
    • ‘ensentences’,句子英考中,读取sentence.json并将key放入题目Entry;
    • ‘cnsentences’,句子英考中,读取sentence.json并将value放入题目Entry;

    if choice.endswith('word'):
        filename = './happylearningini/words.json'
    else:
        filename = './happylearningini/sentences.json'
    

    定义三个button,回调delete、submit和quit&save功能:

    • delete弹窗,提醒用户是否删除。返回True执行json文件读取,删除该数据并覆盖更新文件;

    tk.Button(w1, text='删除本词句', bg='blue', fg='white', command=lambda :\
        delete_items(choice=choice, datas=datas, keylist=keylist, \
                qEntry=qEntry, doneEntry=doneEntry, rightEntry=doneEntry)).grid(row=2,column=1)
    

    check = tk.messagebox.askyesno(title='警告', message='是否将该词句从系统中删除?')
    if not check:
        return
    if choice.startswith('en'):
        key = qEntry.get()
        print(key)
    else:
        key = [k for (k, v) in datas.items() if v == qEntry.get()][0]
    del datas[key]
    if choice.endswith('word'):
        filename = './happylearningini/words.json'
    else:
        filename = './happylearningini/sentences.json'
    with open(filename, mode='wt', encoding='utf-8') as f:
        json.dump(datas,f)
    tk.messagebox.showinfo(title='提醒', message='删除成功。')
    select_test(choice, datas, keylist, qEntry, doneEntry, rightEntry)
    

    • submit弹窗,展示正确答案,让用户选择是否答对,根据选择结果计算成绩;方式为不放回抽样,题库抽空则弹窗提醒终止抽验;
      这里在提交时没有自动判断,主要因为用户写入的作答结果为非标数据,容易引发函数误判;

    tk.Button(w1, text='提交', command=lambda: \
        check_test(choice, datas, keylist, qEntry, answerText, doneEntry, rightEntry, percentEntry)) \
        .grid(row=4, column=0)
    

    done = int(doneEntry.get()[3:])   # 目前共作答了多少道
    right = int(rightEntry.get()[3:])  # 共对了多少道
    answer = answerText.get('1.0', tk.END).strip()
    if choice.startswith('en'):
        result = datas[qEntry.get()]
    else:
        result = [k for (k, v) in datas.items() if v == qEntry.get()]
    check = tk.messagebox.askyesno(title='检查', message=f'{answer}\n正确答案:{result}\n答对了吗?')
    if check:
        done += 1
        right += 1
    else:
        done += 1
    

    • quit读取grade.ini,调出历史成绩与本次成绩计算合并。覆盖历史成绩;

    tk.Button(w1, text='保存测验结果', bg='red', command= lambda :save_grade(choice, doneEntry, rightEntry))\
        .grid(row=4, column=1)
    

    done = int(doneEntry.get()[3:])
    right = int(rightEntry.get()[3:])
    grade_data = []
    with open('./happylearningini/grades.ini', mode='r+t',encoding='utf-8') as f:
        res = f.readline()
        while res:
            if choice.endswith('word'):
                seek = '单词作答量'
            else:
                seek = '句子作答量'
            if res.startswith(seek):
                oldnums, oldpercent, null = res[6:].split('-')
                done += int(oldnums)
                oldpercent = round(float(oldpercent[:-1]) * 0.01,4)
                right += int(int(oldnums) * oldpercent)
                percent = round(right/done,4)
                res = f'{seek}={done}-{percent*100}%-\n'
            grade_data.append(res)
            res = f.readline()
    with open('./happylearningini/grades.ini', mode='wt',encoding='utf-8') as f:
        for i in grade_data:
            f.write(i)
    tk.messagebox.showinfo(title='提醒',message='作答记录已保存。\n【可直接关闭作答页面,无需重复保存】')
    

    【一键初始化】
    os查找当前目录是否存在以下文件,有则清空,无则创建:

    • words.json
    • sentences.json
    • grades.ini

    res = tk.messagebox.askyesno(title='警告!', message='''
        是否初始化程序?
        历史数据都将清除,程序将被重置。“否”取消操作。
        ''', )
    if not res:
        return
    dirs = os.listdir()  # 查询当前的目录是否存在happylearningini文件夹
    if 'happylearningini' in dirs:  # 如果存在就清空happylearningini文件夹
        sondirs = os.listdir('./happylearningini')
        for file in sondirs:
            os.remove(f'./happylearningini/{file}')
    else:  # 不存在就创建空文件夹
        os.mkdir('happylearningini')
    with open('./happylearningini/words.json', mode='wt', encoding='utf-8') as f:
        pass  # 创建初始化的words配置文件
    with open('./happylearningini/sentences.json', mode='wt', encoding='utf-8') as f:
        pass  # 创建初始化的sentences配置文件
    with open('./happylearningini/grades.ini', mode='wt', encoding='utf-8') as f:
        res = '作答数-正确率-\n单词作答量=0-0%-\n句子作答量=0-0%-\n'
        f.write(res)   # 创建初始化的grades配置文件
    tk.messagebox.showinfo(title='提醒', message='初始化成功!\n您可以正常使用了。')
    

    前端效果


    图片1.png
    图片2.png
    图片3.png

    【一些更丰富的构想】

    • 稍加改动可以继续构建更加方便的联网翻译。大致思路为:选择翻译网址,将用户要翻译的内容作为参数带入请求,解析响应结果并展示。再增加一个Button用于回调录入函数,将翻译结果自动保存。
    • 为了增加联网请求的健壮度,这里使用try-except,或者构建一个请求网址pool会更好些,笔者更倾向后者。最后命令符pyinstaller -F filename.py打包成exe(需要提前pip安装打包模块)。
      到此程序的功能就很完善了,快拿去背英语吧

    相关文章

      网友评论

          本文标题:tkinter实践之:写一个测验英语的.exe程序

          本文链接:https://www.haomeiwen.com/subject/goglkdtx.html