po3a  

Python可视化训练

实验目的

l 使学生综合运用图形用户界面设计的概念;

使学生熟悉使用中间面板,组成层次复杂的GUI界面;

l 使学生掌握Python图形绘制和图像处理步骤与方法;

使学生掌握Python可视化处理的步骤、方法与编程

实验环境及实验准备

l 所需硬件环境为微机;

l 所需软件环境为Python 3.X

l 掌握Python下界面容器与基本组件的基本知识与应用;

l 掌握Python下事件处理模型;

l 掌握Python下图形绘制的方法;

实验内容

(一)、设计实现电子算盘,并完成测试

题目描述

给小朋友设计一个电子算盘。要求绘制电子算盘界面,设计并实现打珠算过程(界面参考如下图示)。

界面右侧要求以图形绘制的方式绘制自画像,注意不能是图像文件显示的形式。

 

 

【源代码程序】

import tkinter as tk

from tkinter import Canvas

 

class ElectronicAbacusPlusSelfPortrait:

    def __init__(self, root):

        self.root = root

        self.root.title("Children's Electronic Abacus and Self-portrait")

        self.canvas = tk.Canvas(root, width=800, height=500)  # 修改了画布大小以便更好地展示内容

        self.canvas.pack()

        self.initWindow()  # 绘制棋盘

        self.draw_self_portrait()  # 绘制自画像

        self.bind_bead_events()  # 绑定棋子事件

 

    def initWindow(self):

        # 绘制算盘边框

        self.canvas.create_rectangle(25, 40, 450, 400, width=3)

 

        # 生成串算珠的线

        x0, y0, x1, y1 = 0, 0, 0, 0

        for i in range(5):

            self.canvas.create_line(70 + x0, 40 + y0, 70 + x1, 400 + y1, width=3)

            x0 += 80

            x1 += 80

 

        # 生成上下珠的分割线

        self.canvas.create_line(25, 100, 450, 100, width=3)

 

        # 生成5个上珠

        self.top_oval = [None] * 5

        x0, y0, x1, y1 = 0, 0, 0, 0

        for i in range(5):

            self.top_oval[i] = self.canvas.create_oval(40 + x0, 60 + y0, 100 + x1, 90 + y1, fill='orange', tags=f"top{i}")

            x0 += 80

            x1 += 80

 

        # 生成4*5个下珠

        self.below_oval = [[None] * 5 for _ in range(4)]

        self.chushi = [[None] * 5 for _ in range(4)]

        x0, y0, x1, y1 = 0, 0, 0, 0

        for i in range(4):

            for j in range(5):

                self.below_oval[i][j] = self.canvas.create_oval(40 + x0, 160 + y0, 100 + x1, 190 + y1, fill='yellow', tags=f"below{i}{j}")

                self.chushi[i][j] = self.canvas.coords(self.below_oval[i][j])

                x0 += 80

                x1 += 80

            x0 = 0

            x1 = 0

            y0 += 60

            y1 += 60

 

    def draw_self_portrait(self):

        # 画布右侧绘制自画像,坐标经过调整以适应右侧区域

        # Background

        self.canvas.create_rectangle(550, 0, 800, 500, fill='White Smoke', outline='purple')

 

        # Head

        self.canvas.create_oval(600, 50, 750, 200, fill='Peach Puff')

 

        # Hair

        self.canvas.create_rectangle(600, 50, 750, 90, fill='yellow')  # Top hair

        self.canvas.create_rectangle(580, 90, 610, 130, fill='yellow')  # Left side hair

        self.canvas.create_rectangle(740, 90, 770, 130, fill='yellow')  # Right side hair

 

        # Eyes

        self.canvas.create_oval(630, 100, 650, 120, fill='black')  # Left eye

        self.canvas.create_oval(700, 100, 720, 120, fill='black')  # Right eye

 

        # Mouth

        self.canvas.create_line(640, 170, 710, 170, fill='red')  # Mouth as a simple red line

 

        # Necklace

        self.canvas.create_line(620, 210, 730, 210, fill='black')  # Necklace string

        self.canvas.create_oval(674, 207, 677, 210, fill='Light Pink')  # Small pendant

 

        # Shoulders

        self.canvas.create_line(590, 210, 620, 230, fill='dark grey')  # Left shoulder

        self.canvas.create_line(730, 210, 760, 230, fill='dark grey')  # Right shoulder

 

        # Attire with a floral pattern

        self.canvas.create_rectangle(610, 203, 740, 235, fill='Light Pink')  # Shirt

 

    def get_empty(self):

        empty = [[0 for j in range(5)] for i in range(4)]

        for i in range(4):

            for j in range(5):

                if self.canvas.coords(self.below_oval[i][j]) != self.chushi[i][j]:

                    empty[i][j] = 1

        return empty

 

    def bind_bead_events(self):

        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 = self.get_empty()

            if row == 0:

                if float(self.canvas.coords(content)[1]) - 40 >= 100:

                    self.canvas.move(content, 0, -40)

            else:

                if empty[row - 1][col] == 1:

                    if float(self.canvas.coords(content)[1]) - 40 >= 110 + 10 * (row + 1):

                        self.canvas.move(content, 0, -40)

 

        def handler2(event, fun, row):

            """上珠上划"""

            content = fun  # 这个就是被点击的算珠id

            if float(self.canvas.coords(content)[1]) - 20 >= 40:

                self.canvas.move(content, 0, -20)

 

        def handler3(event, fun, row, col):

            """下珠下划"""

            content = fun  # 这个就是被点击的算珠id

            empty = self.get_empty()

            if row == 3:

                if float(self.canvas.coords(content)[1]) + 40 <= 350:

                    self.canvas.move(content, 0, 40)

            else:

                if empty[row][col] == 1:

                    self.canvas.move(content, 0, 40)

 

        def handler4(event, fun, row):

            """上珠下划"""

            content = fun  # 这个就是被点击的算珠id

            if float(self.canvas.coords(content)[1]) + 20 <= 60:

                self.canvas.move(content, 0, 20)

 

        for i in range(5):

            self.canvas.tag_bind(self.top_oval[i], "<Button-1>", handler_adaptor2(handler2, fun=self.top_oval[i], row=i))

            self.canvas.tag_bind(self.top_oval[i], "<Button-3>", handler_adaptor2(handler4, fun=self.top_oval[i], row=i))

        for i in range(4):

            for j in range(5):

                self.canvas.tag_bind(self.below_oval[i][j], "<Button-1>", handler_adaptor(handler, fun=self.below_oval[i][j], row=i, col=j))

                self.canvas.tag_bind(self.below_oval[i][j], "<Button-3>", handler_adaptor(handler3, fun=self.below_oval[i][j], row=i, col=j))

 

# 创建主窗口

root = tk.Tk()

abacus_and_self_portrait = ElectronicAbacusPlusSelfPortrait(root)

 

# 运行主循环,显示窗口

root.mainloop()

运行测试

 

 

(二)、以(一)中的电子算盘为基础,设计并实现珠算测试器,并完成测试。

题目描述

给小朋友设计一个珠算测试器,要求能够完成珠算加减法的测试。具体的要求功能如下:

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

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

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

(4) 当测试完成,界面显示本次测试情况(包括用户名、测试题目及答题明细、对错情况、测试用时和测试成绩)

【源代码程序】

import tkinter as tk
from tkinter import Canvas, simpledialog, messagebox
import random
import time

class AbacusTestApp:
def __init__(self, root):
self.root = root
self.root.title("Children's Abacus Test")
self.canvas = tk.Canvas(root, width=800, height=500)
self.canvas.pack(side=tk.LEFT)
self.initWindow()
self.questions = []
self.current_question_index = 0
self.correct_answers = 0
self.start_time = None
self.username = ""

self.info_frame = tk.Frame(root)
self.info_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)

self.question_label = tk.Label(self.info_frame, text="Question: ", font=("Arial", 14))
self.question_label.pack()

self.timer_label = tk.Label(self.info_frame, text="Time: 0", font=("Arial", 14))
self.timer_label.pack()

self.result_label = tk.Label(self.info_frame, text="", font=("Arial", 14))
self.result_label.pack()

self.start_button = tk.Button(self.info_frame, text="开始测试", command=self.start_test)
self.start_button.pack(pady=10)

self.submit_button = tk.Button(self.info_frame, text="提交答案", command=self.submit_answer)
self.submit_button.pack(pady=10)


self.bind_bead_events()

def initWindow(self):
# 绘制算盘边框
self.canvas.create_rectangle(25, 40, 450, 400, width=3)

# 生成串算珠的线
x0, y0, x1, y1 = 0, 0, 0, 0
for i in range(5):
self.canvas.create_line(70 + x0, 40 + y0, 70 + x1, 400 + y1, width=3)
x0 += 80
x1 += 80

# 生成上下珠的分割线
self.canvas.create_line(25, 100, 450, 100, width=3)

# 生成5个上珠
self.top_oval = [None] * 5
x0, y0, x1, y1 = 0, 0, 0, 0
for i in range(5):
self.top_oval[i] = self.canvas.create_oval(40 + x0, 60 + y0, 100 + x1, 90 + y1, fill='orange', tags=f"top{i}")
x0 += 80
x1 += 80

# 生成4*5个下珠
self.below_oval = [[None] * 5 for _ in range(4)]
self.chushi = [[None] * 5 for _ in range(4)]
x0, y0, x1, y1 = 0, 0, 0, 0
for i in range(4):
for j in range(5):
self.below_oval[i][j] = self.canvas.create_oval(40 + x0, 160 + y0, 100 + x1, 190 + y1, fill='yellow', tags=f"below{i}{j}")
self.chushi[i][j] = self.canvas.coords(self.below_oval[i][j])
x0 += 80
x1 += 80
x0 = 0
x1 = 0
y0 += 60
y1 += 60

self.bind_bead_events()

def get_empty(self):
empty = [[0 for j in range(5)] for i in range(4)]
for i in range(4):
for j in range(5):
if self.canvas.coords(self.below_oval[i][j]) != self.chushi[i][j]:
empty[i][j] = 1
return empty

def bind_bead_events(self):
def handler_adaptor(handler, fun, row, col):
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):
return lambda event, handler2=handler2, fun=fun, row=row: handler2(event=event, fun=fun, row=row)

def handler(event, fun, row, col):
content = fun
empty = self.get_empty()
if row == 0:
if float(self.canvas.coords(content)[1]) - 40 >= 100:
self.canvas.move(content, 0, -40)
else:
if empty[row - 1][col] == 1:
if float(self.canvas.coords(content)[1]) - 40 >= 110 + 10 * (row + 1):
self.canvas.move(content, 0, -40)

def handler2(event, fun, row):
content = fun
if float(self.canvas.coords(content)[1]) - 20 >= 40:
self.canvas.move(content, 0, -20)

def handler3(event, fun, row, col):
content = fun
empty = self.get_empty()
if row == 3:
if float(self.canvas.coords(content)[1]) + 40 <= 350:
self.canvas.move(content, 0, 40)
else:
if empty[row][col] == 1:
self.canvas.move(content, 0, 40)

def handler4(event, fun, row):
content = fun
if float(self.canvas.coords(content)[1]) + 20 <= 60:
self.canvas.move(content, 0, 20)

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

def start_test(self):
self.username = simpledialog.askstring("Input", "Enter your username:", parent=self.root)
if not self.username:
return

self.questions = self.generate_questions()
self.current_question_index = 0
self.correct_answers = 0
self.start_time = time.time()

self.update_timer()
self.show_question()

def generate_questions(self):
questions = []
for _ in range(5): # 生成5个测试题
a = random.randint(1, 50)
b = random.randint(1, 50)
operation = random.choice(["+", "-"])
if operation == "+":
answer = a + b
else:
answer = a - b
questions.append((a, operation, b, answer))
return questions

def show_question(self):
if self.current_question_index < len(self.questions):
question = self.questions[self.current_question_index]
self.question_label.config(text=f"Question: {question[0]} {question[1]} {question[2]} = ?")
else:
self.end_test()

def submit_answer(self):

# 在这里获取用户通过算盘的输入
user_answer = simpledialog.askstring("Input", "Enter your answer:", parent=self.root)
if not user_answer.isdigit():
messagebox.showerror("Invalid input", "Please enter a valid number.")
return

user_answer = int(user_answer)
correct_answer = self.questions[self.current_question_index][3]

if user_answer == correct_answer:
self.correct_answers += 1

self.current_question_index += 1
self.show_question()
self.update_result_label()

def calculate_abacus_value(self):
value = 0
for i in range(5):
if float(self.canvas.coords(self.top_oval[i])[1]) < 60:
value += 5 * (10 ** (4 - i))
for j in range(4):
if float(self.canvas.coords(self.below_oval[j][i])[1]) < self.chushi[j][i][1]:
value += (j + 1) * (10 ** (4 - i))
return value

def update_result_label(self):
total_questions = len(self.questions)
answered_questions = self.current_question_index
self.result_label.config(text=f"User: {self.username}\n,Total: {total_questions}, Answered: {answered_questions}, Correct: {self.correct_answers}")

def end_test(self):
total_time = time.time() - self.start_time
result_message = f"User: {self.username}\n"
result_message += f"Total Questions: {len(self.questions)}\n"
result_message += f"Correct Answers: {self.correct_answers}\n"
result_message += f"Time Taken: {total_time:.2f} seconds\n"


def update_timer(self):
if self.current_question_index < len(self.questions):
elapsed_time = time.time() - self.start_time
self.timer_label.config(text=f"Time: {int(elapsed_time)}")
self.root.after(1000, self.update_timer)

if __name__ == "__main__":
root = tk.Tk()
app = AbacusTestApp(root)
#submit_button = tk.Button(root, text="提交当前答案", command=app.submit_answer)

submit_button.pack()
root.mainloop()

运行测试

 

posted on   po3a  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
 
点击右上角即可分享
微信分享提示