小学课后服务 Python少儿编程 进阶篇:2-英雄盒子 课件 (31张PPT)

资源下载
  1. 二一教育资源

小学课后服务 Python少儿编程 进阶篇:2-英雄盒子 课件 (31张PPT)

资源简介

(共31张PPT)
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
少儿编程课
王者荣耀英雄盒子
本节我们来制作一个王者荣耀英雄盒子
下面开始王者荣耀英雄盒子的制作
1
首先定义一个窗口,并设置窗口标题
2
运行效果如下
from tkinter import *
# 创建一个窗口
root = Tk()
# 限制窗口大小
root.maxsize(995, 1025)
root.minsize(995, 1025)
# 窗口标题
root.title('王者荣耀英雄选择器')
root.mainloop()
然后在窗口中添加控件
1
定义“全部”按钮,放到窗口中的第一行第一列
2
运行程序,结果如下:
from tkinter import *
# 创建一个窗口
root = Tk()
# 限制窗口大小
root.maxsize(995, 1025)
root.minsize(995, 1025)
# 窗口标题
root.title('王者荣耀英雄选择器')
# 全部
all = Button(root, text='全部')
all.grid(row=0, column=0, padx=30, pady=10)
root.mainloop()
练习
Exercises


线





将剩余的职业按钮编写出来,按钮从左向右依次排列
一起来看下如何做,定义及布局方式如下:
1
让按钮从左向右排列
2
运行效果如下:
# 坦克
is_tank = Button(root, text='坦克')
is_tank.grid(row=0, column=1, padx=30, pady=10)
# 战士
is_warrior = Button(root, text='战士')
is_warrior.grid(row=0, column=2, padx=30, pady=10)
# 刺客
is_assa = Button(root, text='刺客')
is_assa.grid(row=0, column=3, padx=30, pady=10)
# 法师
is_master = Button(root, text='法师')
is_master.grid(row=0, column=4, padx=30, pady=10)
# 射手
is_archer = Button(root, text='射手')
is_archer.grid(row=0, column=5, padx=30, pady=10)
# 辅助
is_sup = Button(root, text='辅助')
is_sup.grid(row=0, column=6, padx=30, pady=10)
注意:grid布局时行号和列号依次为(0,1)、(0,2)、(0,3)、(0,4)、(0,5)、(0,6)
接下来我们加入模糊查询相关的控件:
所谓“模糊查询”是指,当你想要查询某件事物时
不需要输入非常精确地信息,即使是输入这个事物
的一部分信息,也可以查询出来。
1
创建输入框和按钮并加入到窗口中
运行程序,看下效果
2
下面实现模糊查询的界面效果
# 创建输入框
entry = Entry(root)
entry.grid(row=0, column=7, padx=20)
# 确定按钮
commit = Button(root, text='确定')
commit.grid(row=0, column=8)
英雄信息显示
接下来,我们为按钮添加功能,让其能够在被点击之后,使窗口显示图片和英雄名
首先将已经准备好的英雄信息表,复制过来
1
2
hero_info_list = [
{'index_num': 1, 'name': '米莱狄', 'img_path': ".\\hero_img\\米莱狄.jpg", 'is_tank': 0, 'is_warrior': 0, 'is_assa': 0,
'is_master': 1, 'is_archer': 0, 'is_sup': 0},
{'index_num': 2, 'name': '狂铁', 'img_path': ".\\hero_img\\狂铁.jpg", 'is_tank': 0, 'is_warrior': 1, 'is_assa': 0,
.
.
.
{'index_num': 80, 'name': '廉颇', 'img_path': ".\\hero_img\\廉颇.jpg", 'is_tank': 1, 'is_warrior': 0, 'is_assa': 0,
'is_master': 0, 'is_archer': 0, 'is_sup': 0}
]
然后再将英雄图片文件夹复制到项目文件夹下
3
导入Pillow中的Image、ImageTk
from PIL import Image
from PIL import ImageTk
4
创建一个Frame,用于放置英雄图片和姓名标签
Frame
# 创建一个Frame控件,用于布局图片和英雄名
frame = Frame(root)
frame.grid(row=1, column=0, columnspan=10, sticky=W)
这里的stickey属性可以设置控件的排列方式,‘W’表示从最左侧开始排列。
界面已经开发完成,接下来我们将功能实现
def all_callback():
row_num = 0
col_num = 0
for i in hero_info_list:
# 处理图片
img= Image.open(i.get('img_path'))
img= ImageTk.PhotoImage(img)
# 动态生成不同变量名的Label标签
label_img = Label(frame, width=95, height=95, image=img)
label_name = Label(frame, text=i.get('name'))
首先定义回调函数,处理图片并生成标签
1
2
然后使用Grid布局,布局方式如下图:
这里的行号和列号应该怎么写呢,先来看行号
2
10
4
6
8
0
英雄图片的行号每十个变化一次
都是0
2
4
6
8
10
.
.
.
这种偶数
使用一个从0开始每次自增1的数整除10之后在乘2就可以表示( 2 * (row_num // 10) )
英雄名在图片下方,行号每次都比行号多1,所以可以用( 2 * (row_num // 10) + 1 )表示
然后再看下列号的规律:
0
1
2
3
4
5
6
9
8
7
列号自始至终都是从0到9,可以这样去表示:
让一个为0的数,每一次遍历都增加1,当这个数等于10时,我们将它的值重新设为0
最后,我们将回调函数补充完整:
按照我们验证好的布局方式,将回调函数补充完整
def all_callback():
row_num = 0
col_num = 0
for i in hero_info_list:
# 处理图片
img= Image.open(i.get('img_path'))
img= ImageTk.PhotoImage(img)
# 动态生成不同变量名的Label标签
label_img = Label(frame, width=95, height=95, image=img)
label_name = Label(frame, text=i.get('name'))
# 将生成的标签进行布局
# 0 2 4 6 8 10
label_img.grid(row=2 * (row_num // 10), column=col_num)
# 1 3 5 7 9
label_name.grid(row=2 * (row_num // 10) + 1, column=col_num)
row_num += 1
col_num += 1
# 如果列号为10时,重新设为0
if col_num == 10:
col_num = 0
# 重新进入循环
root.mainloop()
1
将回调函数绑定到全部按钮中
# 全部
all = Button(root, text='全部', command=all_callback)
all.grid(row=0, column=0, padx=30, pady=10)
2
完善全部按钮的回调函数,运行效果如下:
为什么图片没有显示呢???
来看一下图片为什么没有显示出来
img1
img1
图片处理
使用pillow处理图片时,当图片处理程序处理完一张图片之后,马上处理下一张图片
由于我们使用的是同一个变量名,所以后一张图片会将前面的覆盖掉,所以图片会显示不出来。
如何解决这个问题呢?
解决英雄图片显示不出来的bug
1
2
再次运行程序,点击全部按钮,问题被解决。
使用locals()[‘img’ + str(row_num)]动态生成变量名,修改代码。
# 处理图片
locals()['img' + str(row_num)] = Image.open(i.get('img_path'))
locals()['img' + str(row_num)] = ImageTk.PhotoImage(locals()['img' + str(row_num)])
# 动态生成不同变量名的Label标签
label_img = Label(frame, width=95, height=95, image=locals()['img' + str(row_num)])
现在继续为第二个按钮,坦克按钮添加功能
1
2
坦克按钮添加回调函数之后,运行程序。
直接复制全部按钮的代码,添加一个判断即可。
def tank_callback():
row_num = 0
col_num = 0
for i in hero_info_list:
if i.get('is_tank'):
# 处理图片
locals()['img' + str(i)] = Image.open(i.get('img_path'))
locals()['img' + str(i)] = ImageTk.PhotoImage(locals()['img' + str(i)])
# 动态生成不同变量名的Label标签
label_img = Label(frame, width=95, height=95, image=locals()['img' + str(i)])
label_name = Label(frame, text=i.get('name'))
# 将生成的标签进行布局
label_img.grid(row=2 * (row_num // 10), column=col_num) # 0 2 4 6 8
label_name.grid(row=2 * (row_num // 10) + 1, column=col_num) # 1 3 5 6 7 9
row_num += 1
col_num += 1
# 如果列号为10时,重新设为0
if col_num == 10:
col_num = 0
# 重新进入事件循环
root.mainloop()
这里复制之后,注意代码的缩进问题。
如何避免重复性工作?
我们可以通过相同的方式去实现其他几个职业按钮的功能
def tank_callback():
row_num = 0
col_num = 0
for i in hero_info_list:
if i.get('is_warrior'):
# 处理图片
locals()['img' + str(i)] = Image.open(i.get('img_path'))
locals()['img' + str(i)] = ImageTk.PhotoImage(locals()['img' + str(i)])
# 动态生成不同变量名的Label标签
label_img = Label(frame, width=95, height=95, image=locals()['img' + str(i)])
label_name = Label(frame, text=i.get('name'))
# 将生成的标签进行布局
label_img.grid(row=2 * (row_num // 10), column=col_num) # 0 2 4 6 8
label_name.grid(row=2 * (row_num // 10) + 1, column=col_num) # 1 3 5 6 7 9
row_num += 1
col_num += 1
# 如果列号为10时,重新设为0
if col_num == 10:
col_num = 0
# 重新进入事件循环
root.mainloop()
def tank_callback():
row_num = 0
col_num = 0
for i in hero_info_list:
if i.get('is_assa'):
# 处理图片
locals()['img' + str(i)] = Image.open(i.get('img_path'))
locals()['img' + str(i)] = ImageTk.PhotoImage(locals()['img' + str(i)])
# 动态生成不同变量名的Label标签
label_img = Label(frame, width=95, height=95, image=locals()['img' + str(i)])
label_name = Label(frame, text=i.get('name'))
# 将生成的标签进行布局
label_img.grid(row=2 * (row_num // 10), column=col_num) # 0 2 4 6 8
label_name.grid(row=2 * (row_num // 10) + 1, column=col_num) # 1 3 5 6 7 9
row_num += 1
col_num += 1
# 如果列号为10时,重新设为0
if col_num == 10:
col_num = 0
# 重新进入事件循环
root.mainloop()
def tank_callback():
row_num = 0
col_num = 0
for i in hero_info_list:
if i.get(‘is_master’):
# 处理图片
。。。
root.mainloop()
def tank_callback():
row_num = 0
col_num = 0
for i in hero_info_list:
if i.get('is_archer'):
# 处理图片
。。。
root.mainloop()
战士
刺客
法师
射手
四段代码唯一不同的地方
如何避免这种重复工作呢
程序结构与代码的优化
现在为止,基本的功能已经全部实现,下面来理清程序逻辑
整体逻辑如下图:
可以发现,在我们将界面编写完成之后,所需要做的只是为按钮添加回调函数
编写界面,可点击的按钮及输入框
为按钮添加回调函数
获得符合条件的英雄信息表
处理信息表中的图片,生成向应标签然后布局
将回调函数绑定到对应的职业按钮
而在回调函数中,所进行的主要操作也只是分为两步:获得正确的信息表和处理图片布局展示
所以我们可以尝试来优化代码
优化思路如下:
定义两个根据不同的情况返回不同英雄信息表的函数
定义统一图片处理、生成标签并布局的函数
点击职业按钮时,根据传入的职业参数返回相应职业英雄信息表的函数
点击确定按钮时,根据输入返回相应英雄信息表的函数
定义主函数,作为所有按钮的回调函数,根据不同的情况,调用不同的函数
函数一
函数二
如果我们点击的是职业按钮,那么调用函数一和布局函数
如果我们点击的是职业按钮,那么调用函数二和布局函数
情况一
情况二
现在按照上面的步骤,编写代码。首先定义一个点击职业按钮后,根据不同参数,返回不同职业的英雄信息列表的函数
def get_hero_list_by_career(career):
# 当点击按钮全部时,直接返回全部的英雄信息列表
if career == 'all':
return hero_info_list
# 根据传入的职业名字筛选
else:
# 并新建英雄信息列表
hero_select_list = []
for i in hero_info_list:
# 判断每一个获取到的英雄是否是这个职业
if i.get(career):
# 将符合条件的添加到新列表中
hero_select_list.append(i)
# 将新的英雄信息列表返回
return hero_select_list
在编写一个点击确定按钮后,根据输入框中的内容返回英雄信息表的函数
def get_hero_list_by_input(entry_text):
hero_list_select = []
# 输入框有内容时,根据输入的内容进行模糊查询
if entry_text:
for i in hero_info_list:
# 判断英雄名中是否包含输入的字符
if i.get('name').find(entry_text) != -1:
# 符合条件的添加到新列表中
hero_list_select.append(i)
# 将新的英雄信息列表返回
return hero_list_select
# 若输入框没有内容且确认按钮被点击,直接返回
else:
return
接着定义一个统一的图片处理、生成标签并布局的函数
def widget_create(select_hero_list):
# 删除原来的控件
for widget in frame.winfo_children():
widget.destroy()
row_num = 0
col_num = 0
# 如果能够获取到英雄信息列表时才开始进行处理
if select_hero_list:
for i in select_hero_list:
# 将每一个图片处理成标签可以接受的类型
locals()['img' + str(col_num)] = Image.open(i.get('img_path'))
locals()['img' + str(col_num)] = ImageTk.PhotoImage(locals()['img' + str(col_num)])
# 创建Label标签,分别显示图片和文字
label_img = Label(frame, width=95, height=95, image=locals()['img' + str(col_num)])
label_name = Label(frame, text=i.get('name'))
# 将创建好的Label标签进行布局
label_img.grid(row=2 * (row_num // 10), column=col_num) # 0 2 4 6 8 10
label_name.grid(row=2 * (row_num // 10) + 1, column=col_num) # 1 3 5 7 9
# 累加
row_num += 1
col_num += 1
# 每当col_num等于10,将它的值重新设为0,保证每一行只显示十个英雄
if col_num == 10:
col_num = 0
# 重新进入事件循环
root.mainloop()
注意:这里的图片处理部分的代码和之前是一样的,可以复制一段过来,然后只添加黄色部分。
上面三个函数编写完成之后,再去定义一个主回调函数
def display_hero(career):
# 当被点击按钮为确定按钮且输入框输入了内容,调用获取英雄列表和创建部件方法
if career == 'commit':
if entry.get():
# 调用根据输入获取列表函数
hero_list = get_hero_list_by_input(entry.get())
# 调用处理图片生成标签并布局展示函数
widget_create(hero_list)
else:
# 如果被点击按钮不是确定按钮,则调用根据职业获取英雄列表函数
hero_list = get_hero_list_by_career(career)
widget_create(hero_list)
最后,我们修改按钮的回调函数属性
为所有按钮设置回调函数并传参
在这里,我们借助了lambda表达式的帮忙,用于传递参数,如果不使用这种方式直接传参,程序将会报错。
all = Button(root, text='全部', command=lambda: display_hero('all'))
is_tank = Button(root, text='坦克', command=lambda: display_hero('is_tank'))
is_warrior = Button(root, text='战士', command=lambda: display_hero('is_warrior'))
is_assa = Button(root, text='刺客', command=lambda: display_hero('is_assa'))
is_master = Button(root, text='法师', command=lambda: display_hero('is_master'))
is_archer = Button(root, text='射手', command=lambda: display_hero('is_archer'))
is_sup = Button(root, text='辅助', command=lambda: display_hero('is_sup'))
commit = Button(root, text='确定', command=lambda: display_hero('commit'))
现在,我们的王者荣耀英雄盒子就制作完成了
运行程序,点击不同的按钮,查看一下效果:
总结
Summary
tkinter中按钮、输入框、标签等控件的使用

第三方库Pillow使用

Thanks!

展开更多......

收起↑

资源预览