10天速通Tkinter库——Day8:《植物杂交实验室》杂交实验及历史记录界面

news2024/11/14 16:40:47

本篇博客我将介绍Tkinter实践项目《植物杂交实验室》中的杂交实验、实验结果和历史记录两个页面的制作。

它们作为主窗口的子页面实例,除了继承主窗口的基础设置(如图标、标题、尺寸等等)、还可以使用主窗口的属性和方法(如数据变量self.hybridizationPlants、页面跳转方法switch_to_screen等等),以及在constants.py中的常量定义和tool.py中定义的通用组件。具体实现见博客10天速通Tkinter库——Day6:《植物杂交实验室》整体框架介绍

目录

1. 杂交实验

1.1 加载背景、返回按钮、关闭按钮 

1.2 初始化杂交实验信息

1.3 杂交实验开始按钮

1.4 选择重置按钮 

1.5 初始化基础植物卡片矩阵

1.6 初始化基础植物卡片选择结果矩阵

 1.7 杂交方式选择

1.8 杂交算法

2. 实验结果

3. 历史记录

3.1 类定义与初始化 

3.2 历史记录数据加载 

3.3 记录显示

one_item 方法

all_record 方法

4. 总结


1. 杂交实验

组件构成如下:

让我们一步一步来实现,定义一个ExperimentScreen类,继承了主界面和tk.Frame。

1.1 加载背景、返回按钮、关闭按钮 

class ExperimentScreen(tk.Frame):
    """植物杂交系统
    
    1. 基础植物卡片矩阵
    2. 基础植物选择框
    3. 杂交方法选择
    4. 杂交实验开始
    """
    def __init__(self, parent):
        super().__init__(parent)
        # 背景和基础组件
        self.breeding_background = create_background(self,experiment_background_path)
        self.close_button = close_button(self,close2_1_path,close2_2_path,clear=2)
        self.back_button = back_button(self,back2_1_path,back2_2_path,clear=2)
  • 初始化父类。
  • 创建了背景 breeding_background 。
  • 创建了关闭按钮 close_button 。
  • 创建了返回按钮 back_button 。

1.2 初始化杂交实验信息

        # 杂交信息
        self.card_choose_photo = [None for _ in range(4)]
        self.card_choose_photo_id = [0,0,0,0]
        self.card_choose_num = 0
        self.method_id = 0
        self.result_plant_id = 0   
        self.result = 0
  • self.card_choose_photo:一个包含 4 个元素的列表,用于存储选择的植物卡片。
  • self.card_choose_photo_id:一个包含 4 个元素的列表,用于存储选择的植物照片的 ID。
  • self.card_choose_num:选择的植物数量。
  • self.method_id:杂交方法的 ID。
  • self.result_plant_id:杂交结果植物的 ID。
  • self.result:杂交结果。

1.3 杂交实验开始按钮

        self.start_button = create_button(self,
                                          dark_image_path=start1_path,
                                          light_image_path=start2_path,
                                          width=351,
                                          height=103,
                                          locate_x=503,
                                          locate_y=455,
                                          command=self.on_start_button_click)

 定义了一个开始按钮,用于在选择植物和杂交方法后开始实验,它的点击事件处理函数如下:

    def on_start_button_click(self):
        """开始杂交实验按钮点击事件"""
        if self.card_choose_photo_id[0]!=0 and self.method_id!=0:
            if (self.method_id==3 or self.method_id==4) and self.card_choose_photo_id[1]!=0:
                worning_music.play()
                messagebox.showinfo("提示", "该杂交方法只能选择单株植物!")
                self.on_clear_button_click()
            else:
                self.on_breeding_method_select()
                self.master.children['result_screen'].result_show(self.result,self.result_plant_id)
                self.on_clear_button_click()
                self.master.switch_to_screen('result_screen')
        elif self.card_choose_photo_id[0]!=0 and self.method_id==0:
            worning_music.play()
            messagebox.showinfo("提示", "请选择杂交方式!")
        else:
            worning_music.play()
            messagebox.showinfo("提示", "请选择基础植物!")

这段代码定义了一个名为 on_start_button_click 的方法,用于处理开始杂交实验按钮的点击事件。

  1. 检查条件

    • 首先检查 self.card_choose_photo_id 是否不为空(即玩家选择了基础植物)且 self.method_id 是否不为零(即玩家选择了杂交方法)。
    • 然后根据 self.method_id 的值进一步检查玩家的选择是否合理。
  2. 错误提示与处理

    • 如果 self.method_id 为 3 或 4(假设这代表特定的杂交方法),并且玩家选择了第二株植物(self.card_choose_photo_id[1] 不为零),则播放警告音乐并显示提示信息,告知只能选择单株植物进行该杂交方法。
    • 如果 self.method_id 为 3 或 4 且玩家未选择第二株植物,则播放警告音乐并显示提示信息,告知玩家需要选择单株植物进行该杂交方法。
    • 如果 self.method_id 为 0(即未选择杂交方法),则播放警告音乐并显示提示信息,告知玩家需要选择杂交方法。
    • 如果 self.card_choose_photo_id[0] 为零(即未选择基础植物),则播放警告音乐并显示提示信息,告知玩家需要选择基础植物。
  3. 执行杂交实验

    • 如果所有条件都满足,调用 self.on_breeding_method_select() 方法执行杂交实验的逻辑。
    • 调用 self.master.children['result_screen'].result_show(self.result,self.result_plant_id) 方法显示结果屏幕,并传递结果和植物ID。
    • 调用 self.on_clear_button_click() 方法清除当前屏幕的任何状态或选择。
    • 使用 self.master.switch_to_screen('result_screen') 方法切换到结果屏幕。

1.4 选择重置按钮 

        self.clear_button = create_button(self,
                                          dark_image_path=clearButton1_path,
                                          light_image_path=clearButton2_path,
                                          width=180,
                                          height=100,
                                          locate_x=590,
                                          locate_y=238,
                                          command=self.on_clear_button_click,
                                          )

定义了一个清空按钮,可以重置我们的选择,它的点击事件处理函数如下:

    def on_clear_button_click(self):
        """清空组件,初始化基础植物选择和杂交方法"""

        self.card_choose_photo_id = [0,0,0,0]
        self.card_choose_num = 0
        self.method_id = 0
        for col in range(4):
            label = tk.Label(self.card_frame,image=self.empty_card,bd=0)
            label.grid(row=0, column=col,sticky="NSEW")      

 这段代码定义了一个名为 on_clear_button_click 的方法,用于处理清除按钮的点击事件。这个方法的主要功能是清空用户界面中与基础植物选择和杂交方法相关的所有组件,并初始化这些选择的状态。

  1. 初始化基础植物选择

    • self.card_choose_photo_id 是一个列表,用于存储用户选择的基础植物图片ID。列表长度为4,意味着它可以存储4个基础植物的选择状态。将列表中的所有元素初始化为0,表示没有选择任何基础植物。
  2. 初始化杂交方法选择

    • self.method_id 是一个变量,用于存储用户选择的杂交方法ID。将其初始化为0,表示没有选择任何杂交方法。
  3. 清空用户界面

    • 使用一个循环遍历 self.card_frame 中的每一列(共4列),这表明用户界面可能包含4个用于选择基础植物的组件。
    • 对于每一列,创建一个标签 (tk.Label),并设置其图像为 self.empty_card(一个空卡牌的图像)。这表示在用户选择基础植物之前,每个选择区域显示为空。
    • bd=0 设置标签的边界为0,使得标签看起来更简洁。
    • 使用 grid 方法将标签放置在界面上,其中 row=0 表示标签位于第一行,column=col 表示标签位于第 col 列,sticky="NSEW" 表示标签将填充其所在的格子,允许在所有方向上伸缩。

1.5 初始化基础植物卡片矩阵

这个和基础植物图鉴的实现方式相同,只是对点击事件进行了修改。

        self.card_button_matrix()
    def card_button_matrix(self):
        """基础植物卡片矩阵"""
        card_frame = tk.Frame(self)
        card_frame.place(x=28,y=88)
        card_frame.config(bg="orange")
        for row in range(6):
            for col in range(8):
                button = tk.Button(card_frame, image=self.master.basal_plant_card[row][col])
                button.config(borderwidth=0,highlightthickness=0)
                button.grid(row=row, column=col,sticky="NSEW")
                def on_click(row, col):
                    card_music.play()
                    if self.card_choose_num ==4 :
                        worning_music.play()
                        messagebox.showinfo("错误", "你最多只能添加四种基础植物!")
                    else:
                        self.card_choose_photo_id[self.card_choose_num] = col+1+row*8
                        self.card_choose_num += 1
                        self.card_choose_frame()
                button.bind('<Button-1>', lambda event, r=row, c=col: on_click(r, c))

这段代码定义了一个名为 card_button_matrix 的方法,用于创建一个基础植物卡片矩阵,并处理卡片点击事件。 

  1. 创建卡片框架

    • card_frame = tk.Frame(self)
    • 创建一个 tk.Frame 实例,作为卡片矩阵的容器,并设置为其父容器 self
    • 使用 place 方法将 card_frame 放置在父容器中的特定位置 (x=28, y=88)
    • card_frame.config(bg="orange")
    • 设置 card_frame 的背景颜色为橙色。
  2. 填充卡片矩阵

    • 使用两个嵌套的 for 循环来遍历行和列,创建卡片按钮。
    • for row in range(6) 和 for col in range(8)
    • 在每个位置创建一个 tk.Button 实例,按钮的图片设置为 self.master.basal_plant_card[row][col],这是从主窗口对象中获取的植物卡片图片。
    • button.config(borderwidth=0,highlightthickness=0)
    • 设置按钮的边框宽度为0,高亮边框宽度也为0,使得按钮看起来没有边框。
    • button.grid(row=row, column=col,sticky="NSEW")
    • 使用 grid 布局管理器将按钮放置在卡片矩阵的相应位置,sticky="NSEW" 表示按钮会粘在单元格的东、南、西、北边缘。
  3. 处理点击事件

    • def on_click(row, col):
    • 定义一个局部函数 on_click,它接受行号 row 和列号 col 作为参数。
    • card_music.play()
    • 当按钮被点击时,播放 card_music
    • 检查 self.card_choose_num 是否等于4:
      • 如果等于4,表示用户已经选择了四种基础植物,此时:
        • worning_music.play()
        • 使用 messagebox.showinfo("错误", "你最多只能添加四种基础植物!")
        • 显示一个警告信息框,告知用户最多只能添加四种基础植物。
      • 如果不等于4,表示用户还可以添加更多基础植物,此时:
        • self.card_choose_photo_id[self.card_choose_num] = col+1+row*8
        • 将选中的植物卡片ID存储在 self.card_choose_photo_id 数组中,其中 col+1+row*8 是根据行和列计算出的卡片ID。
        • self.card_choose_num += 1
        • 增加已选择植物卡片的数量。
        • self.card_choose_frame()
        • 调用 self.card_choose_frame() 方法,可能用于更新界面或处理卡片选择逻辑。
  4. 绑定点击事件

    • button.bind('<Button-1>', lambda event, r=row, c=col: on_click(r, c))
    • 将 <Button-1> 事件(即鼠标左键点击)绑定到 on_click 函数上,其中 r=row 和 c=col 是传递给 on_click 函数的参数。

1.6 初始化基础植物卡片选择结果矩阵

 我们使用一个1*4的矩阵存储选择的基础植物卡片。当然了,还是老样子,空的部分我们用空白卡片填充

        # 基础植物卡片和选择框初始化
        self.empty_card = self.empty_card_load()
    def empty_card_load(self):
        """空白卡片加载"""
        image = Image.open(emptycard_path)
        image = image.resize((78, 100), Image.Resampling.LANCZOS)
        photo = ImageTk.PhotoImage(image)
        return photo    

组件实现如下:

  self.card_choose_frame()
    def card_choose_frame(self):
        """基础植物卡片选择框"""
        self.card_frame = tk.Frame(self,bd=0)
        self.card_frame.place(x=518,y=138)
        for col in range(4):
            if col < self.card_choose_num:
                self.card_choose_photo[col] = image_load(78,100,basal_card_path,self.card_choose_photo_id[col],".jpg")
                label = tk.Label(self.card_frame,image=self.card_choose_photo[col] ,bd=0)
                label.grid(row=0, column=col,sticky="NSEW")
            else:
                label = tk.Label(self.card_frame,image=self.empty_card,bd=0)
                label.grid(row=0, column=col,sticky="NSEW")    

这段代码定义了一个名为 card_choose_frame 的方法,用于创建和显示用户已选择的基础植物卡片选择框。 

  1. 创建卡片选择框架

    • self.card_frame = tk.Frame(self, bd=0)
    • 创建一个 tk.Frame 实例,作为卡片选择框的容器,并设置其父容器为 selfbd=0 表示没有边框。
    • self.card_frame.place(x=518, y=138)
    • 使用 place 方法将 self.card_frame 放置在父容器中的特定位置 (x=518, y=138)
  2. 填充卡片选择框

    • 使用 for 循环遍历列,从0到3(因为 col 范围是0到3,对应于最多4张卡片的选择)。
    • if col < self.card_choose_num:
      • 如果当前列号 col 小于 self.card_choose_num,表示用户已经选择了足够的卡片。
        • self.card_choose_photo[col] = image_load(78,100,basal_card_path,self.card_choose_photo_id[col],".jpg")
          • 调用 image_load 函数加载图片,将图片设置为卡片选择框中相应卡片的图片。参数包括图片的宽度和高度(78x100),卡片路径(basal_card_path),卡片ID(self.card_choose_photo_id[col])和文件扩展名(.jpg)。
        • label = tk.Label(self.card_frame, image=self.card_choose_photo[col], bd=0)
          • 创建一个 tk.Label 实例,用于显示卡片图片,并设置边框宽度为0。
        • label.grid(row=0, column=col, sticky="NSEW")
          • 使用 grid 布局管理器将标签放置在卡片选择框的相应位置,sticky="NSEW" 表示标签会粘在单元格的东、南、西、北边缘。
    • else:
      • 如果当前列号 col 大于或等于 self.card_choose_num,表示用户尚未选择足够的卡片。
        • label = tk.Label(self.card_frame, image=self.empty_card, bd=0)
          • 创建一个 tk.Label 实例,用于显示一个空卡片图片,self.empty_card 应该是一个空卡片的图片对象。
        • label.grid(row=0, column=col, sticky="NSEW")
          • 使用 grid 布局管理器将标签放置在卡片选择框的相应位置。

 1.7 杂交方式选择

self.method_choose_optionmenu()
    def method_choose_optionmenu(self):
        """杂交方法选择"""
        def on_option_change(value):
            self.method_id = options.index(value) + 1
        options = [" 基础杂交方式 ",
                   " 使用强化药剂 ", 
                   " 单株辐射变异 ",
                   " 注射僵尸血清 ",
                   " 使用神奇魔法 "]
        
        selected_value = tk.StringVar()
        selected_value.set(" 杂交方式选择 ")
        option_menu = tk.OptionMenu(self, selected_value, *options, command=on_option_change,)
        option_menu.config(font=("华文新魏", 29, "bold"),
                           bg="darkslategray",activebackground="gray",
                           fg="limegreen", activeforeground="lime",
                           borderwidth=0, highlightthickness=0)
        menu = option_menu['menu']
        menu.config(bg="darkslategray", fg="lime", font=("华文新魏", 25, "bold"))
        option_menu.place(x=530, y=386)

这段代码定义了一个名为 method_choose_optionmenu 的方法,用于创建一个下拉菜单(OptionMenu),让用户从预定义的杂交方法中选择一个选项。

  1. 内部函数定义

    • def on_option_change(value):
      • 定义了一个内部函数 on_option_change,该函数在选项改变时被调用。
      • self.method_id = options.index(value) + 1
      • 当选项改变时,将选择的选项的索引加1后赋值给 self.method_id。这通常用于将用户的选择转换为一个整数标识符,以便程序可以识别。
  2. 定义选项列表

    • options = [" 基础杂交方式 ", " 使用强化药剂 ", " 单株辐射变异 ", " 注射僵尸血清 ", " 使用神奇魔法 "]
    • 定义了一个名为 options 的列表,包含了下拉菜单中的所有选项。
  3. 创建 StringVar 对象

    • selected_value = tk.StringVar()
    • 创建了一个 tk.StringVar 对象,用于跟踪下拉菜单中当前选中的值。
    • selected_value.set(" 杂交方式选择 ")
    • 初始化 selected_value,将其设置为下拉菜单的默认选项。
  4. 创建 OptionMenu 控件

    • option_menu = tk.OptionMenu(self, selected_value, *options, command=on_option_change,)
    • 创建一个 tk.OptionMenu 控件,它允许用户从给定的选项中选择一个。
    • self 作为父容器传递给 OptionMenu,使下拉菜单能够正确地放置在GUI中。
    • *options 将 options 列表中的元素解包,作为选项传递给 OptionMenu
    • command=on_option_change 指定当用户选择一个选项时调用的函数。
  5. 配置 OptionMenu 控件

    • option_menu.config(...)
    • 使用 config 方法对 option_menu 进行配置,包括:
      • 字体样式和大小:font=("华文新魏", 29, "bold")
      • 背景和活动背景颜色:bg="darkslategray", activebackground="gray"
      • 文本颜色和活动文本颜色:fg="limegreen", activeforeground="lime"
      • 边框和突出显示宽度:borderwidth=0, highlightthickness=0
  6. 配置菜单的菜单项

    • menu = option_menu['menu']
    • 获取 option_menu 的菜单对象。
    • menu.config(bg="darkslategray", fg="lime", font=("华文新魏", 25, "bold"))
    • 对菜单项进行配置,设置背景、文本颜色和字体样式。
  7. 放置 OptionMenu 控件

    • option_menu.place(x=530, y=386)
    • 使用 place 方法将 option_menu 控件放置在父容器中的特定位置 (x=530, y=386)

1.8 杂交算法

这也是开始按钮的点击事件处理

    def on_breeding_method_select(self):
        """杂交实验: 数据匹配
        
        1. 匹配杂交方法, 成功则:
            a. 匹配规则:
                规则1-4: 亲本植物是否为玩家选择的子集,是则杂交成功
                规则5: 产生一个随机数, 匹配随机植物
            b. 判断是否为新植物, 是则result=0,否则result=1
        2. 失败则: result=2
        3. 跳转至结果界面
        4. 修改杂交植物数据, 添加杂交记录
        """
        def is_subset(list1, list2):
            # 子集判断
            return all(item in list2 for item in list1)
        def is_new(type):
            # 是否为新植物判断
            if type: return 0
            else: return 1

        sign = False
        random_integer = random.randint(0, 6)
        num = 0
        for plant in self.master.hybridizationPlants:
            if plant.get("hybridization_method")==self.method_id: 
                if self.method_id!=5:
                    sign = is_subset(plant.get("parent_base_plant_ids"),self.card_choose_photo_id)
                    if sign==True: break
                else:
                    if num==random_integer:
                        sign=True
                        break
                    else:
                        num += 1
        if sign:
            success_music.play()
            self.result_plant_id = plant.get("id")
            self.result = is_new(plant.get("new_hybrid"))
            self.master.hybridizationPlants[self.result_plant_id-1]["new_hybrid"] = False
        else:
            fail_music.play()
            self.result = 2
            self.result_plant_id = 0
        self.add_record()

    def add_record(self):
        # 添加杂交记录
        record = {  
                    "id": len(self.master.recorditem)+1,
                    "parent_base_plant_ids": self.card_choose_photo_id,
                    "hybridization_method": self.method_id,
                    "hybridization_plant_id": self.result_plant_id   
                }
        self.master.recorditem.append(record)

定义了一个名为 on_breeding_method_select 的方法,用于处理杂交实验中的数据匹配和结果处理。

  1. 定义内部函数

    • def is_subset(list1, list2):
      • 定义了一个内部函数 is_subset,用于判断一个列表是否是另一个列表的子集。
    • def is_new(type):
      • 定义了一个内部函数 is_new,用于判断一个植物是否为新植物。
  2. 初始化变量

    • sign = False
      • 初始化一个标志变量 sign,用于表示杂交是否成功。
    • random_integer = random.randint(0, 6)
      • 生成一个 0 到 6 之间的随机整数。
    • num = 0
      • 初始化一个计数器变量 num
  3. 遍历杂交植物

    • 通过遍历 self.master.hybridizationPlants 列表中的每个植物。
    • 对于每个植物,检查其杂交方法是否与当前选择的方法 self.method_id 匹配。
    • 如果方法不是 5,则使用 is_subset 函数检查亲本植物是否为玩家选择的子集。如果是,则设置标志变量 sign 为 True,并退出循环。
    • 如果方法是 5,则使用计数器 num 和随机整数 random_integer 来模拟随机匹配。如果计数器等于随机整数,则设置标志变量 sign 为 True,并退出循环。
  4. 处理杂交结果

    • 如果标志变量 sign 为 True,表示杂交成功。
    • 播放成功音乐。
    • 获取杂交成功的植物的 ID,并将其存储在 self.result_plant_id 变量中。
    • 使用 is_new 函数判断植物是否为新植物,并将结果存储在 self.result 变量中。
    • 将杂交成功的植物的 new_hybrid 属性设置为 False
    • 如果标志变量 sign 为 False,表示杂交失败。
    • 播放失败音乐。
    • 将 self.result 设置为 2,表示杂交失败。
    • 将 self.result_plant_id 设置为 0。
  5. 添加杂交记录

    • 调用 add_record 方法添加杂交记录。
    • 创建一个包含杂交记录信息的字典 record
    • 将记录的 ID 设置为当前记录数量加 1。
    • 将亲本植物的 ID 列表设置为玩家选择的照片 ID。
    • 将杂交方法设置为当前选择的方法。
    • 将杂交植物的 ID 设置为杂交成功的植物的 ID。
    • 将记录添加到 self.master.recorditem 列表中。

2. 实验结果

 其实共有三种结果:

  1. 杂交出来新植物
  2. 杂交出了已拥有植物,如上图
  3. 杂交失败

class ResultScreen(tk.Frame):
    """杂交结果界面"""
    def __init__(self, parent):
        super().__init__(parent)
        self.breeding_background = create_background(self,result_background_path)
        self.back_button = create_button(self,
                                         dark_image_path=result_back1_path,
                                         light_image_path=result_back2_path,
                                         width=85,
                                         height=25,
                                         locate_x=24,
                                         locate_y=567,
                                         command=self.on_back_button_click)
        self.result_plant = None
        self.result_text = [None, None, None]
        self.result_text_load()
        self.pack()

    def result_text_load(self):
        """加载结果的三种情况"""
        for col in range(3):
            self.result_text[col] = image_load(300,90,result_path,col+1,".png")

    def on_back_button_click(self):
        """返回植物杂交界面"""
        self.master.children['experiment_screen'].on_clear_button_click()
        self.master.switch_to_screen('experiment_screen')

    def result_show(self,result,result_plants_id):
        """result: 
            0. 新植物
            1. 已经获得
            2. 杂交失败
        """
        self.label1 = tk.Label(self,image=self.result_text[result],bd=0)
        self.label1.place(x=290,y=362)

        if result_plants_id!=0:
            self.result_plant = image_load(114,156,hybrid_card_path,result_plants_id,".jpg")
        else:
            image = Image.open(emptyresult_path)
            image = image.resize((114, 156), Image.Resampling.LANCZOS)
            self.result_plant = ImageTk.PhotoImage(image)
        self.label2 = tk.Label(self,image=self.result_plant,bd=0)
        self.label2.place(x=382,y=123)

这段代码定义了一个名为 ResultScreen 的类,用于创建植物杂交结果的界面。这个界面包含了用于显示杂交结果的图像、返回按钮以及用于加载和显示结果文本的功能。 

初始化方法 __init__

  • 初始化背景:通过调用 create_background 函数创建一个背景图像,并将其设置为 self.breeding_background
  • 创建返回按钮:使用 create_button 函数创建一个按钮,该按钮在用户点击时调用 on_back_button_click 方法返回到植物杂交界面。
  • 初始化结果变量:设置 self.result_plant 为 None,用于存储显示的杂交结果植物图像。同时,初始化 self.result_text 为一个包含三个 None 的列表,用于存储结果文本的图像。
  • 加载结果文本:调用 result_text_load 方法来加载结果的文本图像。
  • 布局:使用 pack 方法将界面组件添加到父窗口中。

result_text_load 方法

  • 加载结果文本:遍历列表的三个元素,为每种结果情况加载相应的文本图像,并存储在 self.result_text 列表中。

on_back_button_click 方法

  • 返回到植物杂交界面:通过调用 master.children['experiment_screen'].on_clear_button_click() 清空实验屏幕的组件,并使用 master.switch_to_screen('experiment_screen') 切换回植物杂交界面。

result_show 方法

  • 显示结果:根据 result 参数的值显示不同的结果图像。如果结果为 0(表示新植物),则显示新植物的图像;如果结果为 1(表示已获得),则显示已获得植物的图像;如果结果为 2(表示杂交失败),则显示失败的图像。
  • 显示杂交结果植物:根据 result_plants_id 参数的值加载并显示杂交结果植物的图像。如果 result_plants_id 为 0,表示没有结果植物,因此使用空图像。

3. 历史记录

历史记录这个模块略微复杂,因为涉及一个切页操作,并且每一条历史记录数据都是单独呈现的

3.1 类定义与初始化 

class RecordScreen(tk.Frame):
    """杂交记录界面
    1. 每页3条记录
    2. 最多3页记录
    """
    def __init__(self, parent):
        super().__init__(parent)
        self.breeding_background = create_background(self,record_background_path)
        self.close_button = close_button(self,close1_1_path,close1_2_path)
        self.back_button = back_button(self,back1_1_path,back1_2_path)
        self.ahead_buttton = create_button(self,
                                           dark_image_path=ahead2_1_path,
                                           light_image_path=ahead2_2_path,
                                           width=110,
                                           height=27,
                                           locate_x=330,
                                           locate_y=564,
                                           command=self.on_ahead_button_click)
        self.ahead_buttton = create_button(self,
                                           dark_image_path=next2_1_path,
                                           light_image_path=next2_2_path,
                                           width=110,
                                           height=27,
                                           locate_x=450,
                                           locate_y=564,
                                           command=self.on_next_button_click)
        
        self.page = 0
        self.record_num = 0
        self.empty_card = self.empty_card_load()
        self.empty_method = self.empty_method_load()
        self.all_record(page=0)
        self.pack()

    def empty_card_load(self):
        # 加载空白卡片
        image = Image.open(emptycard_path)
        image = image.resize((78, 100), Image.Resampling.LANCZOS)
        photo = ImageTk.PhotoImage(image)
        return photo  
    def empty_method_load(self):
        # 加载空白方法
        image = Image.open(emptymethod_path)
        image = image.resize((175, 100), Image.Resampling.LANCZOS)
        photo = ImageTk.PhotoImage(image)
        return photo        
    
    def on_ahead_button_click(self):
        if self.page!=0:
            self.page -= 1
            self.all_record(self.page)
            self.pack()
    def on_next_button_click(self):
        if self.page!=2 and (self.record_num-3*(self.page+1))>0:
            self.page += 1
            self.all_record(self.page)
            self.pack()

 这段代码定义了一个名为 RecordScreen 的类,用于创建植物杂交记录的界面。这个界面允许用户浏览最多3页的记录,每页显示3条记录。

初始化方法 __init__

  • 初始化背景:通过调用 create_background 函数创建一个背景图像,并将其设置为 self.breeding_background
  • 创建按钮:创建关闭按钮、返回按钮以及用于跳转到上一页和下一页的按钮。这些按钮分别调用 close_buttonback_buttonon_ahead_button_click 和 on_next_button_click 方法。
  • 初始化页面和记录数:设置 self.page 为 0,表示当前显示第一页记录;设置 self.record_num 为 0,表示记录总数。
  • 加载空白卡片和空白方法:通过调用 empty_card_load 和 empty_method_load 方法加载空白卡片和空白方法的图像,并存储在 self.empty_card 和 self.empty_method 中。
  • 加载所有记录:调用 all_record 方法初始化显示的记录,并使用 pack 方法将界面组件添加到父窗口中。

empty_card_load 方法

  • 加载空白卡片:从指定路径加载空白卡片的图像,调整尺寸,并转换为 ImageTk.PhotoImage 格式以便在界面上显示。

empty_method_load 方法

  • 加载空白方法:与 empty_card_load 类似,从指定路径加载空白方法的图像,调整尺寸,并转换为 ImageTk.PhotoImage 格式。

on_ahead_button_click 方法

  • 跳转到上一页:如果当前页不是第一页,减小 self.page 的值,调用 all_record 方法重新加载记录,并使用 pack 方法重新布局界面。

on_next_button_click 方法

  • 跳转到下一页:如果当前页不是最后一页,并且还有更多记录可以显示,增加 self.page 的值,调用 all_record 方法重新加载记录,并使用 pack 方法重新布局界面。

3.2 历史记录数据加载 

    def data_load(self):
        """加载杂交记录数据"""
        records = self.master.recorditem
        records = records[::-1]
        self.basal_plants_card = [[None for _ in range(4)] for _ in range(9)]
        self.hybrid_plants_card = [None for _ in range(9)] 
        self.method = [None for _ in range(9)] 
        self.record_num = 0
        for index, item in enumerate(records):
            basal_plant_card = item.get("parent_base_plant_ids")
            for col in range(len(basal_plant_card)):
                if basal_plant_card[col]!=0:
                    self.basal_plants_card[index][col] = image_load(78,100,basal_card_path,basal_plant_card[col],".jpg")
            if item.get("hybridization_plant_id")!=0:
                self.hybrid_plants_card[index] = image_load(78,100,hybrid_card_path,item.get("hybridization_plant_id"),".jpg")
            self.method[index] = image_load(175,100,method_path,item.get("hybridization_method"),".png")
            self.record_num += 1
            if index==8: break

data_load 方法是 RecordScreen 类的一个方法,用于加载杂交记录数据。以下是该方法的详细解释:

方法目的

  • 加载保存在 self.master.recorditem 中的杂交记录数据,并将这些数据用于界面显示。

方法步骤

  1. 反转记录列表:将 self.master.recorditem 中的记录列表反转,这是因为希望最新的记录显示在最前面。

  2. 初始化卡片和方法列表

    • self.basal_plants_card:创建一个9行4列的二维列表,用于存储基础植物卡片的图像,每行对应一条记录,每列对应一个基础植物。
    • self.hybrid_plants_card:创建一个9元素的列表,用于存储杂交植物卡片的图像,每个元素对应一条记录。
    • self.method:创建一个9元素的列表,用于存储杂交方法的图像,每个元素对应一条记录。
  3. 初始化记录数:将 self.record_num 设置为0,用于记录已加载的记录数量。

  4. 遍历记录:遍历反转后的记录列表 records,对每条记录执行以下操作:

    • 加载基础植物卡片:从记录中获取基础植物ID列表 basal_plant_card,然后遍历这个列表,对于每个非零ID,调用 image_load 函数加载对应的图像,并将其存储在 self.basal_plants_card 对应的位置。
    • 加载杂交植物卡片:如果记录中的杂交植物ID不为零,调用 image_load 函数加载对应的图像,并将其存储在 self.hybrid_plants_card 对应的位置。
    • 加载杂交方法:调用 image_load 函数加载对应的杂交方法图像,并将其存储在 self.method 对应的位置。
    • 更新记录数:每次循环结束时,增加 self.record_num 的值。
  5. 终止条件:如果已经遍历了9条记录,则终止循环。

3.3 记录显示

    def one_item(self,id):
        """展示一条数据: 亲本植物+杂交方法+杂交植物"""
        line = id% 3 

        #  亲本植物
        self.card_frame = tk.Frame(self,bd=0)
        self.card_frame.place(x=156,y=108+line*155)
        for col in range(4):
            if self.basal_plants_card[id][col]!=None:
                label = tk.Label(self.card_frame,image=self.basal_plants_card[id][col] ,bd=0)
                label.grid(row=0, column=col,sticky="NSEW")
            else:
                label = tk.Label(self.card_frame,image=self.empty_card,bd=0)
                label.grid(row=0, column=col,sticky="NSEW")         

        # 杂交方法
        if self.method[id]!=None:
            label2 = tk.Label(self,image=self.method[id],bd=0)
        else:
            label2 = tk.Label(self,image=self.empty_method,bd=0)
        label2.place(x=475,y=line*155+109)
        
        # 杂交植物
        if self.hybrid_plants_card[id]!=None:
            label3 = tk.Label(self,image=self.hybrid_plants_card[id],bd=0)
        else:
            label3 = tk.Label(self,image=self.empty_card,bd=0)
        label3.place(x=654,y=line*155+109)

    def all_record(self,page=0):
        self.data_load()
        self.one_item(0+page*3)
        self.one_item(1+page*3)
        self.one_item(2+page*3)
    

one_item 和 all_record 是两个用于展示数据的方法,它们可能是 tkinter GUI 应用程序中的一部分,用于在一个图形用户界面中展示杂交记录的详细信息。

one_item 方法

这个方法用于展示一条具体的记录,它包含以下步骤:

  1. 计算行位置:通过 id % 3 计算出记录应该显示的行位置。

  2. 创建并放置卡片框架:创建一个 tk.Frame 对象 self.card_frame,然后根据行位置将其放置在界面上。

  3. 展示亲本植物卡片

    • 遍历 self.basal_plants_card[id] 列表,对于每个非空的图像,创建一个 tk.Label 并将其放置在框架中。
    • 如果某个位置是空的(即 None),则显示一个空卡片图像。
  4. 展示杂交方法

    • 如果 self.method[id] 不为空,则创建一个 tk.Label 来展示对应的图像。
    • 如果为空,则展示一个空的方法图像。
  5. 展示杂交植物卡片

    • 如果 self.hybrid_plants_card[id] 不为空,则创建一个 tk.Label 来展示对应的图像。
    • 如果为空,则展示一个空卡片图像。

all_record 方法

这个方法用于展示所有记录,它包含以下步骤:

  1. 加载数据:调用 self.data_load() 方法来加载杂交记录数据。

  2. 展示记录:根据给定的页面 page 参数,调用 self.one_item 方法来展示每条记录。每页显示3条记录,通过 page*3 计算出当前页的第一条记录的索引。

4. 总结

到这里整个项目的全部内容就结束了,今天我们实现了杂交实验、实验结果、杂交记录三个界面。杂交实验重点在于植物卡片的选择、杂交方法的选择,以及匹配算法;杂交记录则是在数据加载和展示部分略微复杂一点。

下期预告:我将对博客进行汇总,介绍我使用到的工具,以及将代码和数据文件放在GitHub仓库。

感谢大家支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2081963.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IoTDB 如何有效实现磁盘 I/O 监控和优化?

IoTDB 监控工具&#xff1a;有效保障读写数据量与系统效率&#xff01; 磁盘 I/O 负载过高的原因是什么&#xff1f;如何排查&#xff1f; 如何判断磁盘 I/O 是否成为系统瓶颈&#xff1f; 如何优化磁盘 I/O 读写性能&#xff1f; 在现代计算机系统和应用程序中&#xff0c;磁盘…

[000-002-01].第26节:MySQL对隔离级别的实现

1.MySQL支持的四种隔离级别&#xff1a; 2.如何设置事务的隔离级别 3.不同隔离级别举例 3.1.演示1. 读未提交之脏读 3.2.演示2&#xff1a;读已提交 3.3.演示3&#xff1a;设置隔离级别为可重复读&#xff0c;事务的执行流程如下&#xff1a; 3.4.演示4&#xff1a;幻读:

3 Python开发工具:VSCode+插件

本文是 Python 系列教程第 3 篇&#xff0c;完整系列请查看 Python 专栏。 Visual Studio Code的安装非常简单&#xff0c;就不放这里增加文章篇幅了。 相比PyCharm&#xff0c;VSCode更加轻量&#xff0c;启动速度快。并且搭配Python插件就能实现和Pycharm一样的代码提示、高…

在手机在线预览3D模型,是如何实现的?

在手机在线预览3D模型&#xff0c;主要依赖于几个关键技术和步骤来实现。以下是一个概括性的流程&#xff1a; 一、模型上传 选择平台&#xff1a;首先&#xff0c;用户需要选择一个支持3D模型在线预览的平台&#xff0c;如51建模网、Sketchfab等。这些平台通常提供用户友好的…

iPhone不停重启怎么办?全面解析与解决方案

iPhone作为当今最受欢迎的智能手机之一&#xff0c;其稳定性和流畅性一直备受用户赞誉。然而&#xff0c;有时我们可能会遇到iPhone不停重启的问题&#xff0c;这不仅影响了正常使用&#xff0c;还可能让我们感到焦虑和困扰。本文将为大家详细解析iPhone不停重启的原因&#xf…

常用的编写VBA的软件 (L*00K)

一、Microsoft Office套件 Microsoft Excel&#xff1a; Excel是VBA编程最为广泛使用的环境之一。用户可以通过编写宏来自动化重复性的任务&#xff0c;如数据整理、自动填充、复杂的计算等。Excel中的VBA功能让用户能够创建复杂的函数、表单以及完整的应用程序&#xff0c;以…

html+css网页设计 个人网站模版 我的书屋5个页面

htmlcss网页设计 个人网站模版 我的书屋5个页面 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 …

华为大动作:三折折叠屏手机9月亮相,价格破万引猜疑

在科技迅猛发展的今天&#xff0c;智能手机的形态和功能不断突破传统边界&#xff0c;为用户带来前所未有的体验。华为&#xff0c;作为全球通信领域的领军企业&#xff0c;一直在折叠屏技术上推陈出新。 近日&#xff0c;华为即将发布的首款三折折叠屏手机成为了市场的焦点&a…

ICD-Face:用于人脸识别的类内紧致蒸馏算法

ICD-Face: Intra-class Compactness Distillation for Face Recognition 摘要 在ICD-Face中&#xff0c;首先提出计算教师和学生模型的相似度分布&#xff0c;然后引入特征库来构造足够多的高质量的正对。然后&#xff0c;估计教师和学生模型的概率分布&#xff0c;并引入相似…

全钢无边防静电地板结构特点你了解多少

机房装修常常会用到防静电地板&#xff0c;全钢无边防静电地板作为其中一种&#xff0c;常用于对地板外观要求较高&#xff0c;且不需要频繁更换设备的场所&#xff0c;那么全钢无边防静电地板有哪些特点呢&#xff1f; 先来说一下全钢无边防静电地板的结构&#xff1a;全钢无…

大模型的那些道道

1 AI大模型介绍 chat-gpt、sora、sd、文心一言&#xff08;GAI&#xff0c;生成式AI&#xff09;等等&#xff0c;这些是大模型嘛&#xff0c;准确来说这些只是大模型落地的产品&#xff1b;“大模型”通常指的是拥有大量参数的深度学习模型&#xff1b;因此对计算资源要求很高…

可编程逻辑控制器故障排除

通常&#xff0c;逻辑控制器中大多数问题的根源可以缩小到以下区域之一的故障&#xff1a; 1. 处理器模块 2. 输入 3. 输出 4. 梯形图逻辑程序 除了使用万用表检查电源电压&#xff08;假设您知道所需的 IO&#xff09;之外&#xff0c;您还必须检查每个区域是否存在特定故…

Qt_qrc文件管理资源

qrc使用方式 1.在项目中创建一个qrc文件 文件名不要带中文和特殊符号 2.把图片导入到qrc文件中 所谓"前缀"可以理解成虚拟的目录&#xff0c;这个目录没有在你的电脑真实存在,是Qt自己抽象出来的&#xff0c;qrc机制本质上就是把图片的二进制数据&#xff0c;转成C代…

SeaweedFS 分布式存储

一、简介 SeaweedFS 是一种多功能且高效的存储系统&#xff0c;旨在满足现代系统管理员管理 blob、对象、文件和数据仓库存储需求的需求。无论数据集的大小如何&#xff0c;其架构都能保证快速访问时间&#xff0c;磁盘寻道时间为常数时间 (O(1))。这使其成为速度和效率至关重…

实验设计不好搞?ChatGPT少不了!【附示例】

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 实验设计是确保研究科学性和可靠性的关键环节。然而&#xff0c;许多同学在进行毕业论文实验设计时&#xff0c;常常面临选题、变量确定、实验流程规划等诸多挑战。ChatGPT能够提供全方…

联想小新 Pro 16:AI启航版,定义笔记本性能新高度

联想小新 Pro 16 AI元启版笔记本以其搭载的英特尔酷睿Ultra 9-185H处理器&#xff0c;16核心22线程的豪华配置&#xff0c;成为市场上的性能巨擘。搭配32GB LPDDR5x RAM和1TB PCIe 4.0 SSD&#xff0c;这款笔记本在处理高负载任务时展现出无与伦比的流畅性&#xff0c;无论是图…

基于大数据分析景区消费行为影响因素研究【消费等级预测、携程,去哪网数据抓取】

有需要本项目的可以私信博主&#xff0c;讲解、部署 目录 摘要.... 1 Abstract 2 1引言... 3 1.1 研究背景... 3 1.2 国内外研究现状... 4 1.3 研究目的... 5 1.4 研究意义... 6 2 关键技术理论介绍... 7 2.1 网络爬虫... 7 2.2 Python介绍... 8 2.3 随机森林... 9…

three.js渲染中文的3D字体

下载中文字体 引入下面的代码 点击下载 提取码: lywa <!DOCTYPE html> <html lang"en"><head><title>three.js webgl - modifier - tessellation</title><meta charset"utf-8"><meta name"viewport" c…

哪个牌子的电容笔好用?2024开学季深度测评五款高人气平替电容笔

​随着数字化时代的到来&#xff0c;众多工作和学习活动都转向了线上平台。这一趋势推动了电容笔市场的迅速扩张&#xff0c;吸引了众多新品牌加入竞争。面对市场上琳琅满目的选择&#xff0c;消费者在挑选可能会感到更加困难&#xff0c;不知道到底哪个牌子的电容笔好用。作为…

FL Studio24.1.1.4239无限试用版安装包下载!快来尝鲜吧!

在音乐制作领域&#xff0c;FL Studio一直以其强大的功能和用户友好的界面受到广大音乐制作人的喜爱。最近&#xff0c;它的版本更新到了24.1.1.4239&#xff0c;这次更新带来了许多令人兴奋的新功能和改进&#xff0c;让音乐创作变得更加轻松和有趣。 FL Studio21汉化版下载网…