资源简介 (共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)英雄信息显示接下来,我们为按钮添加功能,让其能够在被点击之后,使窗口显示图片和英雄名首先将已经准备好的英雄信息表,复制过来12hero_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、ImageTkfrom PIL import Imagefrom PIL import ImageTk4创建一个Frame,用于放置英雄图片和姓名标签Frame# 创建一个Frame控件,用于布局图片和英雄名frame = Frame(root)frame.grid(row=1, column=0, columnspan=10, sticky=W)这里的stickey属性可以设置控件的排列方式,‘W’表示从最左侧开始排列。界面已经开发完成,接下来我们将功能实现def all_callback():row_num = 0col_num = 0for 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'))首先定义回调函数,处理图片并生成标签12然后使用Grid布局,布局方式如下图:这里的行号和列号应该怎么写呢,先来看行号2104680英雄图片的行号每十个变化一次都是0246810...这种偶数使用一个从0开始每次自增1的数整除10之后在乘2就可以表示( 2 * (row_num // 10) )英雄名在图片下方,行号每次都比行号多1,所以可以用( 2 * (row_num // 10) + 1 )表示然后再看下列号的规律:0123456987列号自始至终都是从0到9,可以这样去表示:让一个为0的数,每一次遍历都增加1,当这个数等于10时,我们将它的值重新设为0最后,我们将回调函数补充完整:按照我们验证好的布局方式,将回调函数补充完整def all_callback():row_num = 0col_num = 0for 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 10label_img.grid(row=2 * (row_num // 10), column=col_num)# 1 3 5 7 9label_name.grid(row=2 * (row_num // 10) + 1, column=col_num)row_num += 1col_num += 1# 如果列号为10时,重新设为0if 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完善全部按钮的回调函数,运行效果如下:为什么图片没有显示呢???来看一下图片为什么没有显示出来img1img1图片处理使用pillow处理图片时,当图片处理程序处理完一张图片之后,马上处理下一张图片由于我们使用的是同一个变量名,所以后一张图片会将前面的覆盖掉,所以图片会显示不出来。如何解决这个问题呢?解决英雄图片显示不出来的bug12再次运行程序,点击全部按钮,问题被解决。使用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)])现在继续为第二个按钮,坦克按钮添加功能12坦克按钮添加回调函数之后,运行程序。直接复制全部按钮的代码,添加一个判断即可。def tank_callback():row_num = 0col_num = 0for 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 8label_name.grid(row=2 * (row_num // 10) + 1, column=col_num) # 1 3 5 6 7 9row_num += 1col_num += 1# 如果列号为10时,重新设为0if col_num == 10:col_num = 0# 重新进入事件循环root.mainloop()这里复制之后,注意代码的缩进问题。如何避免重复性工作?我们可以通过相同的方式去实现其他几个职业按钮的功能def tank_callback():row_num = 0col_num = 0for 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 8label_name.grid(row=2 * (row_num // 10) + 1, column=col_num) # 1 3 5 6 7 9row_num += 1col_num += 1# 如果列号为10时,重新设为0if col_num == 10:col_num = 0# 重新进入事件循环root.mainloop()def tank_callback():row_num = 0col_num = 0for 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 8label_name.grid(row=2 * (row_num // 10) + 1, column=col_num) # 1 3 5 6 7 9row_num += 1col_num += 1# 如果列号为10时,重新设为0if col_num == 10:col_num = 0# 重新进入事件循环root.mainloop()def tank_callback():row_num = 0col_num = 0for i in hero_info_list:if i.get(‘is_master’):# 处理图片。。。root.mainloop()def tank_callback():row_num = 0col_num = 0for 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 = 0col_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 10label_name.grid(row=2 * (row_num // 10) + 1, column=col_num) # 1 3 5 7 9# 累加row_num += 1col_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'))现在,我们的王者荣耀英雄盒子就制作完成了运行程序,点击不同的按钮,查看一下效果:总结Summarytkinter中按钮、输入框、标签等控件的使用√第三方库Pillow使用√Thanks! 展开更多...... 收起↑ 资源预览