一实验目的
l 使学生综合运用图形用户界面设计的概念;
l 使学生熟悉使用中间面板,组成层次复杂的GUI界面;
l 使学生掌握Python图形绘制和图像处理步骤与方法;
l 使学生掌握Python可视化处理的步骤、方法与编程;
二实验环境及实验准备
l 所需硬件环境为微机;
l 所需软件环境为Python 3.X等;
l 掌握Python下界面容器与基本组件的基本知识与应用;
l 掌握Python下事件处理模型;
l 掌握Python下图形绘制的方法;
三实验内容
(一)、设计实现电子算盘,并完成测试
【题目描述】
给小朋友设计一个电子算盘。要求绘制电子算盘界面,设计并实现打珠算过程(界面参考如下图示)。
界面右侧要求以图形绘制的方式绘制自画像,注意不能是图像文件显示的形式。
【源代码程序】
from tkinter import *
def initWindow():
rect = canvas.create_rectangle(25, 40, 450, 400, width=5) # 算盘边框
x0, y0, x1, y1 = 0, 0, 0, 0
line_fenge = canvas.create_line(25, 100, 450, 100, width=5) # 生成上下珠的分割线
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
print(chushi)
num = [[0 for i in range(5)] for j in range(4)] # 五个下珠分别对应的数值
num2 = [0 for i in range(5)] # 五个上珠分别对应的数值
canvas.create_oval(750, 370, 470, 90, fill='yellow')
canvas.create_oval(500, 170, 560, 200, fill='black')
canvas.create_oval(650, 170, 710, 200, fill='black')
canvas.create_arc(500, 200, 700, 300, start=-150, extent=120, style=ARC, width=5)
def get_empty():
empty = [[0 for j in range(5)] for i in range(4)]
for i in range(4):
for j in range(5):
if canvas.coords(below_oval[i][j]) != chushi[i][j]:
empty[i][j] = 1
print(empty)
return empty
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
empty = get_empty()
if row == 0:
if float(canvas.coords(content)[1]) - 40 >= 100:
canvas.move(content, 0, -40)
else:
if empty[row - 1][col] == 1:
if float(canvas.coords(content)[1]) - 40 >= 110 + 10 * (row + 1):
canvas.move(content, 0, -40)
def handler2(event, fun, row):
"""上珠上划"""
content = fun # 这个就是被点击的算珠id
if float(canvas.coords(content)[1]) - 20 >= 40:
canvas.move(content, 0, -20)
def handler3(event, fun, row, col):
"""下珠下划"""
content = fun # 这个就是被点击的算珠id
empty = get_empty()
if row == 3:
if float(canvas.coords(content)[1]) + 40 <= 350:
canvas.move(content, 0, 40)
else:
if empty[row][col] == 1:
canvas.move(content, 0, 40)
def handler4(event, fun, row):
"""上珠下划"""
content = fun # 这个就是被点击的算珠id
if float(canvas.coords(content)[1]) + 20 <= 60:
canvas.move(content, 0, 20)
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()
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)] # 所有下珠的初始坐标
initWindow()
bind()
window.mainloop()
【运行测试】
(二)、以(一)中的电子算盘为基础,设计并实现珠算测试器,并完成测试。
【题目描述】
给小朋友设计一个珠算测试器,要求能够完成珠算加减法的测试。具体的要求功能如下:
(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=5) # 算盘边框
x0, y0, x1, y1 = 0, 0, 0, 0
line_fenge = canvas.create_line(25, 100, 450, 100, width=5) # 生成上下珠的分割线
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="#FFFFFF", 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=10, height=2, 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="#FFFFFF", 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="#FFFFFF", 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="#FFFFFF", 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="#FFFFFF", 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. Pillow (Pillow Imaging Library)
特点:
易用性:Pillow 是 Python Imaging Library (PIL) 的一个分支,专为简单图像处理任务设计,如基本的裁剪、旋转、滤镜应用等。
文件格式支持广泛:支持多种图像格式的读写,包括常见的 JPEG、PNG、BMP 等。
基本操作:适合于图像的加载、保存、显示、基本变换等。
实例代码(打开并显示图片):
1from PIL import Image
2
3# 打开图像
4img = Image.open('example.jpg')
5# 显示图像
6img.show()
2. OpenCV (Open Source Computer Vision Library)
特点:
计算机视觉:OpenCV 是一个强大的计算机视觉库,特别适合于实时图像处理、视频分析、特征检测、机器学习等高级应用。
性能:底层用 C++ 编写,提供了高效的算法,适合于计算密集型任务。
高级功能:包含人脸检测、物体识别、图像分割等高级功能。
实例代码(灰度转换):
1import cv2
2
3# 读取图像
4img = cv2.imread('example.jpg')
5# 转换为灰度图像
6gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
7# 显示图像
8cv2.imshow('Gray Image', gray_img)
9cv2.waitKey(0) # 等待按键后关闭窗口
10cv2.destroyAllWindows()
3. scikit-image
特点:
科学图像处理:scikit-image 面向科学研究和工程应用,提供了一系列高级算法,如图像分割、几何变换、滤波、形态学处理等。
与科学计算库集成:与 NumPy、SciPy 紧密集成,便于进行复杂的数学运算和数据分析。
模块化:提供模块化的设计,易于扩展和定制。
1from skimage import io, exposure
2
3# 读取图像
4img = io.imread('example.jpg')
5# 直方图均衡化
6eq_img = exposure.equalize_hist(img)
7# 显示图像
8io.imshow(eq_img)
9io.show()
异同点总结
易用性和目标用户:Pillow 最为简单直观,适合初学者和基本图像处理需求;OpenCV 功能强大且深入,更适合于计算机视觉和复杂图像分析;scikit-image 则侧重于科研和工程领域的高级图像处理。
性能:OpenCV 由于其底层的 C++ 实现,在处理速度上通常优于其他两个库,特别是在大规模图像处理和视频处理时。
功能范围:Pillow 覆盖了基本的图像处理操作;OpenCV 包含更多计算机视觉相关的高级功能;scikit-image 则提供了大量科学图像分析的工具。
社区和文档:三个库都拥有活跃的社区和良好的文档支持,但因为 OpenCV 和 scikit-image 的专业性,相关资源可能更偏向于特定领域。
标签:canvas,window,4.29,range,fun,oval,row From: https://www.cnblogs.com/szm123/p/18256977