珠算测试器

题目描述】设计一个珠算测试器,要求能够完成珠算加减法的测试。具体的要求功能如下:

(1)用户启动测试,输入用户名后系统随机生成特定数目的加减法测试题;

(2) 要求测试使用表盘式或数字时秒表进行界面计时显示;

(3) 对于每道测试题目,要求用户使用电子算盘完成珠算过程,当按下确认键时,将珠算结果与正确答案比对,并在界面上显示总题数、已答题数和已做对题数;

(4) 当测试完成,界面显示本次测试情况(包括用户名、测试题目及答题明细、对错情况、测试用时和测试成绩)。
【练习要求】请给出源代码程序和运行测试结果,源代码程序要求添加必要的注释。

from tkinter import *
import tkinter.messagebox as msg
from random import randint

def initWindow():
rect = canvas.create_rectangle(25, 40, 450, 400, width=3) # 算盘边框
x0, y0, x1, y1 = 0, 0, 0, 0
for i in range(5): # 生成串算珠的线
line_shu = canvas.create_line(70 + x0, 40 + y0, 70 + x1, 400 + y1, width=3)
x0 += 80
x1 += 80
line_fenge = canvas.create_line(25, 100, 450, 100, width=3) # 生成上下珠的分割线
x0, y0, x1, y1 = 0, 0, 0, 0
for i in range(5): # 生成5个上珠
top_oval[i] = canvas.create_oval(40 + x0, 60 + y0, 100 + x1, 90 + y1, fill='orange', tags=f"top{i}")
x0 += 80
x1 += 80
x0, y0, x1, y1 = 0, 0, 0, 0
for i in range(4): # 生成4*5个下珠
for j in range(5):
below_oval[i][j] = canvas.create_oval(40 + x0, 160 + y0, 100 + x1, 190 + y1, fill='yellow', tags=f"below{i}{j}")
chushi[i][j] = canvas.coords(below_oval[i][j])
x0 += 80
x1 += 80
x0 = 0
x1 = 0
y0 += 60
y1 += 60
global start_button, label_sum, username, entry_username, username_text, window_showusername
global label_time, window_time, window_question
global var_username, var_question, var_msg, window_answer, window_msg
sum = Label(window, width=20, height=2, bg="grey", textvariable=var, font=('Arial', 14))
label_sum = canvas.create_window(750, 80, window=sum, anchor=NE)
canvas.itemconfigure(label_sum, state="hidden")

button = Button(window, width=30, height=4, bg="grey", text="开始测试吧!", command=adjust)
start_button = canvas.create_window(750, 300, window=button, anchor=NE)

text = Label(window, text="用户名:", width=10, height=2, bg="white")
username_text = canvas.create_window(500, 200, window=text, anchor=CENTER)

username = Entry(window, font=('Arial', 14))
entry_username = canvas.create_window(640, 200, window=username, anchor=CENTER)

label_showusername = Label(window, textvariable=var_username, width=15, height=2, bg="grey", font=('Arial', 14))
window_showusername = canvas.create_window(770, 0, window=label_showusername, anchor=NE)
canvas.itemconfigure(window_showusername, state="hidden")

label_time = Label(window, width=10, height=2, bg="grey", font=('Arial', 14))
window_time = canvas.create_window(600, 0, window=label_time, anchor=NE)
canvas.itemconfigure(window_time, state="hidden")

label_question = Label(window, width=30, height=2, bg="grey", font=('Arial', 14), textvariable=var_question)
window_question = canvas.create_window(630, 180, window=label_question, anchor=CENTER)
canvas.itemconfigure(window_question, state="hidden")

answer_button = Button(window, width=10, height=2, bg="grey", text="提交答案", command=judge, font=('Arial', 14))
window_answer = canvas.create_window(630, 400, window=answer_button, anchor=CENTER)
canvas.itemconfigure(window_answer, state="hidden")

msg_label = Label(window, width=30, height=6, bg="grey", font=('Arial', 14), textvariable=var_msg)
window_msg = canvas.create_window(630, 260, window=msg_label, anchor=CENTER)
canvas.itemconfigure(window_msg, state="hidden")

def run_time(target):
def counting():
global time
time += 1
global li
print(li)
if li != 5:
target.config(text=f"所用时间:{str(time)}s")
else:
target.config(text="游戏结束")
target.after(1000, counting) # 间隔1000毫秒再次执行counting函数
counting()

def adjust():
global ques, li, true, false, all_username
myusername = username.get()
all_username = myusername
if myusername != "":
"""对画布中的部件进行一些调整"""
for i in range(5):
ques[i] = get_question()
canvas.itemconfigure(label_sum, state="normal")
canvas.itemconfigure(window_showusername, state="normal")
canvas.itemconfigure(window_time, state="normal")
canvas.itemconfigure(window_question, state="normal")
canvas.itemconfigure(window_answer, state="normal")
canvas.itemconfigure(window_msg, state="normal")
var_question.set(f"问题:{ques[0][0]}")
run_time(label_time)
var_username.set(f"用户名:{myusername}")
sum = get_sum()
var.set(f"当前数值:{sum}")
var_msg.set(f"总题数:5\n已经做了0题\n已做对0题\n已做错0题")
canvas.itemconfigure(start_button, state="hidden")
canvas.itemconfigure(entry_username, state="hidden")
canvas.itemconfigure(username_text, state="hidden")
else:
msg.showinfo("错误", "用户名不能为空白")
def judge():
def next():
var_question.set(f"问题:{ques[li][0]}")
global li, false, true
sum = get_sum()
myanw[li][0] = ques[li][0]
myanw[li][1] = sum
if sum == int(ques[li][1]):
true += 1
msg.showinfo("答案正确", f"恭喜你做对了")
else:
false += 1
msg.showinfo("答案错误", f"做错了!正确答案是{ques[li][1]}")
li += 1
var_msg.set(f"总题数:5\n已经做了{li}题\n已做对{true}题\n已做错{false}题")
if li != 5:
next()
else:
msg.showinfo("游戏结束", f"以下是你的战绩\n总题数:5\n总用时:{time}s\n总成绩:{true * 20}分\n做对了{true}题\n做错了{false}题")
msg.showinfo("游戏结束", f"{all_username},你好\n以下是你的答题明细\n总题数:5\n1.{myanw[0][0]}={myanw[0][1]}\n"
f"2.{myanw[1][0]}={myanw[1][1]}\n3.{myanw[2][0]}={myanw[2][1]}\n"
f"4.{myanw[3][0]}={myanw[3][1]}\n5.{myanw[4][0]}={myanw[4][1]}\n")
exit()

def get_question():
answer, num1, num2 = 0, 0, 0
operator = ""
temp = randint(1, 2)
if temp == 1:
while 1:
num1 = randint(0, 99999)
num2 = randint(0, 99999)
if num1 + num2 <= 99999:
break
answer = num1 + num2
operator = "+"
elif temp == 2:
while 1:
num1 = randint(0, 99999)
num2 = randint(0, 99999)
if num1 - num2 > 0:
break
answer = num1 - num2
operator = "-"
equation = str(num1) + operator + str(num2)
return equation, answer
def get_sum():
sum = 0
temp = 5
for i in range(5):
temp -= 1
if num2[i] == 1:
sum += 10 ** temp * 5
temp = 5
for j in range(5):
temp -= 1
for i in range(4):
if num[i][j] == 1:
sum += 10 ** temp
return sum

def bind():
def handler_adaptor(handler, fun, row, col):
"""事件处理函数的适配器,相当于中介,可以帮助tag_bind函数传递参数"""
return lambda event, handler=handler, fun=fun, col=col, row=row: handler(event=event, fun=fun, row=row, col=col)

def handler_adaptor2(handler2, fun, row):
"""事件处理函数的适配器,相当于中介,可以帮助tag_bind函数传递参数"""
return lambda event, handler2=handler2, fun=fun, row=row: handler2(event=event, fun=fun, row=row)

def handler(event, fun, row, col):
"""下珠上划"""
content = fun # 这个就是被点击的算珠id
if row == 0:
if float(canvas.coords(content)[1]) - 40 >= 100 and num[row][col] == 0:
canvas.move(content, 0, -40)
num[row][col] = 1
else:
if num[row - 1][col] == 1:
if float(canvas.coords(content)[1]) - 40 >= 110 + 10 * (row + 1) and num[row][col] == 0:
canvas.move(content, 0, -40)
num[row][col] = 1
sum = get_sum()
var.set(f"当前数值:{sum}")

def handler2(event, fun, row):
"""上珠上划"""
content = fun # 这个就是被点击的算珠id
if float(canvas.coords(content)[1]) - 20 >= 40:
canvas.move(content, 0, -20)
num2[row] = 1
sum = get_sum()
var.set(f"当前数值:{sum}")

def handler3(event, fun, row, col):
"""下珠下划"""
content = fun # 这个就是被点击的算珠id
if row == 3:
if num[row][col] == 1:
canvas.move(content, 0, 40)
num[row][col] = 0
else:
if num[row + 1][col] == 0 and num[row][col] == 1:
canvas.move(content, 0, 40)
num[row][col] = 0
sum = get_sum()
var.set(f"当前数值:{sum}")

def handler4(event, fun, row):
"""上珠下划"""
content = fun # 这个就是被点击的算珠id
if float(canvas.coords(content)[1]) + 20 <= 60:
canvas.move(content, 0, 20)
num2[row] = 0
sum = get_sum()
var.set(f"当前数值:{sum}")

for i in range(5):
canvas.tag_bind(top_oval[i], "<Button-1>", handler_adaptor2(handler2, fun=top_oval[i], row=i))
canvas.tag_bind(top_oval[i], "<Button-3>", handler_adaptor2(handler4, fun=top_oval[i], row=i))
for i in range(4):
for j in range(5):
canvas.tag_bind(below_oval[i][j], "<Button-1>", handler_adaptor(handler, fun=below_oval[i][j], row=i, col=j))
canvas.tag_bind(below_oval[i][j], "<Button-3>", handler_adaptor(handler3, fun=below_oval[i][j], row=i, col=j))

if __name__ == "__main__":
window = Tk()
window.title("电子算盘")
window.geometry("800x500")
canvas = Canvas(window, width="800", height="500", bg="white")
canvas.pack()
ques = [0 for i in range(5)]
myanw = [[0, 0]for i in range(5)]
li = 0
time, true, false = 0, 0, 0
start_button, label_sum, username, entry_username = 0, 0, 0, 0
username_text, window_showusername, window_time = 0, 0, 0
label_time, window_question, window_answer = 0, 0, 0
all_username = ""
window_msg = 0
var = StringVar()
var_username = StringVar()
var_question = StringVar()
var_msg = StringVar()
top_oval = [int for i in range(5)] # 定义列表存储5个上珠
below_oval = [[int for i in range(5)] for i in range(4)] # 定义列表存储4*5个下珠
chushi = [[0 for j in range(5)] for i in range(4)] # 所有下珠的初始坐标
num = [[0 for i in range(5)] for j in range(4)] # 4*5个下珠分别是否被拨动
num2 = [0 for i in range(5)] # 五个上珠分别是否被拨动
initWindow()
bind()
window.mainloop()

增补博客 第六篇 python 电子算盘的更多相关文章

  1. 一鼓作气 博客--第六篇 note6

    1.无论公司付给你多少,你的青春都是廉价的!! 2.通往财富自由之路 --得到APP 3.time 3.1 time.time() t = time.time() print(t) #--->1 ...

  2. Scrum 冲刺博客第六篇

    一.当天站立式会议照片一张 二.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中 昨天已完成的工作 判断用户输入的答案是否正确并将其输出到界面中 今天计划完成的工作 对排行榜 ...

  3. [转]有哪些值得关注的技术博客(Java篇)

    有哪些值得关注的技术博客(Java篇)   大部分程序员在自学的道路上不知道走了多少坑,这个视频那个网站搞得自己晕头转向.对我个人来说我平常在学习的过程中喜欢看一些教程式的博客.这些博客的特点: 1. ...

  4. Django 系列博客(六)

    Django 系列博客(六) 前言 本篇博客介绍 Django 中的路由控制部分,一个网络请求首先到达的就是路由这部分,经过路由与视图层的映射关系再执行相应的代码逻辑并将结果返回给客户端. Djang ...

  5. # Do—Now——团队冲刺博客_总结篇

    Do-Now--团队冲刺博客_总结篇 目录 博客链接 作者 1. 第一篇(领航篇) @仇夏 2. 第二篇 @侯泽洋 3. 第三篇 @仇夏 4. 第四篇 @周亚杰 5. 第五篇 @唐才铭 6. 第六篇 ...

  6. JavaScript 系列博客(六)

    JavaScript 系列博客(六) 前言 本篇博客介绍 js 操作高级,通过 js 获取标签的全局属性.设置标签的全局属性,以及事件的绑定与取消.js 盒模型与 js 动画. 对象使用的高级 对象的 ...

  7. 基于 abp vNext 和 .NET Core 开发博客项目 - 终结篇之发布项目

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  8. 年度十佳 DevOps 博客文章(前篇)

    如果说 15 年你还没有将 DevOps 真正应用起来,16 年再不实践也未免太落伍了.国内 ITOM 领军企业 OneAPM 工程师为您翻译整理了,2015 年十佳 DevOps 文章,究竟是不是深 ...

  9. 为了确认是您本人在申请搬家,请在原博客发表一 篇标题为《将博客搬至CSDN》的文章,并将文章地址填写在上方的"搬家通知地址"中

    为了确认是您本人在申请搬家,请在原博客发表一 篇标题为<将博客搬至CSDN>的文章,并将文章地址填写在上方的"搬家通知地址"中

  10. thinkphp5项目--个人博客(六)

    thinkphp5项目--个人博客(六) 项目地址 fry404006308/personalBlog: personalBloghttps://github.com/fry404006308/per ...

随机推荐

  1. 最佳实践|Spring Boot 应用如何快速接入 Prometheus 监控

    ​简介:SpringBoot 微服务的开发.发布与部署只占其生命周期的一小部分,应用和系统运维才是重中之重.而运维过程中,监控工作更是占据重要位置.那么,为了对系统的状态进行持续地观测,面向Sprin ...

  2. PolarDB for PostgreSQL 开源路线图

    ​简介:作者:蔡乐 本文主要分享一下Polar DB for PG的开源路线图,虽然路线图已经拟定,但是作为开源产品,所有参与者都能提出修改意见,包括架构核心特性的技术以及周边生态和工具等,希望大家能 ...

  3. dotnet 6 使用 DependentHandle 关联对象生命周期

    本文将告诉大家在 dotnet 6 新加入的 System.Runtime.DependentHandle 的类型的使用方法,通过 DependentHandle 可以实现将某个对象的引用生命周期和另 ...

  4. games101-3 BRDF101

    BRDF101 概述 本文基于知乎Maple对brdf的文章,在此基础又收集了一些其它来源的关于brdf的文章,希望能够完全理解记忆相关知识 关于Jakub Boksansky的文章,看的过程中又去搜 ...

  5. STLINK/V2下载器接线方法

    一.ST-LINK ST-LINK产品如下图所示: ST-LINK接口定义如下图所示 ST-LINK与stm32接线 使用SW接法只需要四根线: STM32 ST-LINK VCC(3.3V) TVC ...

  6. 使用Vue3在浏览器端进行zip文件压缩

    在前端开发中,我们时常需要处理文件上传和下载的功能.有时,用户可能希望将多个文件打包成一个zip文件以便于下载.今天,我将分享一个使用Vue3和JSZip库在浏览器端实现zip文件压缩的示例. 首先, ...

  7. [WC/CTS2024] 线段树 题解

    Link 纪念一下场切题. 题意:给定一棵(分点不一定为中点)的线段树,给定若干个询问区间,问有多少个线段树上结点的集合,知道了这些结点对应的区间和就可以知道任何一个询问区间的和. 从询问区间开始考虑 ...

  8. 【项目学习】Timeswap:第一个完全去中心化的基于 AMM 的货币市场协议

    总览 Timeswap 是世界上第一个完全去中心化的基于 AMM 的货币市场协议,无需预言机或清算人即可工作. Timeswap 采用 3 变量来维持 AMM 的运作.它通过允许用户决定他们的风险状况 ...

  9. AeroAdmin、TeamViewer和Splashtop Business Access的区别

    ​Hi everyone! 今天又是喜闻乐见的吃瓜时间,王婆卖瓜,不得不夸. 炎炎夏日,就给大家送个大西瓜吧.望梅止渴也是极好的. ------官宣分割线------ Splashtop是针对个人和企 ...

  10. C 语言编程 — 输入/输出与文件操作

    目录 文章目录 目录 前文列表 输入/输出 scanf() 和 printf() getchar() 和 putchar() 文件操作 打开文件 关闭文件 写入文件 读取文件 二进制 I/O 函数 前 ...