class GridCrafterView(tk.Frame): """A tkinter widget used to display crafting with a grid as input and a single cell as output""" def __init__(self, master, input_size, mode="normal"): """Constructor Parameters: master (tk.Frame | tk.Toplevel | tk.Tk): Tkinter parent widget input_size (tuple<int, int>): The (row, column) size of the grid crafter's input grid """ super().__init__(master) # check mode if mode not in ["normal", "smelting"]: raise NotImplementedError("Not supported mode") # Task 2.2 Crafting: Create widgets here self._input = SelectableGrid(rows=input_size[0], columns=input_size[1]) self._input_view = ItemGridView(self, self._input.get_size()) self._output = SelectableGrid(rows=1, columns=1) if mode == "smelting": self._button = tk.Button(self, text="=>Smelt=>", height=1) im = Image.open('fire.jpg') self.img = ImageTk.PhotoImage(im) # img = tk.PhotoImage(file="fire.gif") self._label = tk.Label(self, image=self.img) self._label.pack(side=tk.LEFT) else: self._button = tk.Button(self, text="=>Craft=>", height=1) self._input_view.pack(side=tk.LEFT) self._button.pack(side=tk.LEFT) self._output_view = ItemGridView(self, (1, 1)) self._output_view.pack(side=tk.LEFT) self._input_view.render(self._input.items(), self._input.get_selected()) self._output_view.render(self._output.items(), self._output.get_selected()) def render(self, key_stack_pairs, selected): """Renders the stacks at appropriate cells, as determined by 'key_stack_pairs' Parameters: key_stack_pairs (tuple<*, Stack>): (key, stack) pairs, where each stack should be drawn at the cell corresponding to key selected (*): The key that is currently selected, or None if no key is selected """ # Task 2.2 Crafting: Create widgets here print(f"{selected} is selected") for key, stack in key_stack_pairs: print(f"Redrawing {stack} at {key}") if key == "output": # Task 2.2 Crafting: Draw output cell self._output_view.draw_cell((0, 0), stack, selected == "output") else: # Task 2.2 Crafting: Draw input cells self._input_view.draw_cell(key, stack, True if selected == key else False) def bind_for_id(self, event, callback): """Binds callback to tkinter mouse event Callback accept parameters: callback(key, event), where - key (*) is the key of the cell clicked, etc. - mouse_event (tk.MouseEvent) is the original mouse event from tkinter """ if event not in TK_MOUSE_EVENTS: return self._input_view.bind_for_id(event, callback) self._output_view.bind(event, lambda e: callback("output", e)) self._button.bind(event, lambda e: callback("craft", e))
class GridCrafterView(tk.Frame): """A tkinter widget used to display crafting with a grid as input and a single cell as output""" def __init__(self, master, input_size): """Constructor Parameters: master (tk.Frame | tk.Toplevel | tk.Tk): Tkinter parent widget input_size (tuple<int, int>): The (row, column) size of the grid crafter's input grid """ super().__init__(master) # Task 2.2 Crafting: Create widgets here # ... self._input_grid = ItemGridView(self, input_size) self._input_grid.pack(side=tk.LEFT) self._crafter_button = tk.Button(self, text="=> Craft =>") self._crafter_button.pack(side=tk.LEFT) self._output_grid = ItemGridView(self, (1, 1)) self._output_grid.pack(side=tk.LEFT) def render(self, key_stack_pairs, selected): """Renders the stacks at appropriate cells, as determined by 'key_stack_pairs' Parameters: key_stack_pairs (tuple<*, Stack>): (key, stack) pairs, where each stack should be drawn at the cell corresponding to key selected (*): The key that is currently selected, or None if no key is selected """ # Task 2.2 Crafting: Create widgets here # ... #print(f"{selected} is selected") for key, stack in key_stack_pairs: #print(f"Redrawing {stack} at {key}") if key == "output": # Task 2.2 Crafting: Draw output cell # ... self._output_grid.draw_cell((0, 0), stack, selected == "output") else: # Task 2.2 Crafting: Draw input cells # ... self._input_grid.draw_cell(key, stack, key == selected) def bind_for_id(self, event, callback): """Binds callback to tkinter mouse event Callback accept parameters: callback(key, event), where - key (*) is the key of the cell clicked, etc. - mouse_event (tk.MouseEvent) is the original mouse event from tkinter """ if event not in TK_MOUSE_EVENTS: return # Task 2.2 Crafting: Bind to tkinter widgets here # When a cell is clicked, we need to call the callback. Tkinter's bind does # this for us, but not exactly how we want. Tkinter bound callbacks have a single # parameter, the mouse event containing useful information about the click (i.e. # the x & y coordinates) # # However, x & y coordinates aren't that useful. The class controlling this widget # (i.e. CraftingWindow) only needs to know which cell was clicked. It's not # concerned with where it was clicked, just that it was. This is so it can easily # interact with the crafter model (i.e. GridCrafter) and move stacks around or # select/deselect them. # # To integrate with CraftingWindow, you will need to transform the callback # provided to tk.bind, exactly as is done in ItemGridView.bind_for_id, except # the first argument may not necessarily be a (row, column) position, but # simply an arbitrary key (for basic 2x2 crafting, the 5 keys are: # "output", (0, 0), (0, 1), (1, 0), (1, 1) # # ... self._input_grid.bind_for_id(event, callback) self._output_grid.bind(event, lambda e: callback("output", e)) self._crafter_button.bind(event, lambda e: callback("craft", e))