📋 Section 9: Menu + Difficulty

📝 Summary

In this section, you will add a menu bar to your Tkinter app. The menu will let the player pick a difficulty, restart the game, quit the app, and open an “About” dialog.

✅ Checklist

  • Add a _make_menu() method inside class GameApp (after __init__) in app.py.
  • Create a menubar and attach it to the window.
  • Build a Game menu with difficulty presets from settings.py.
  • Use lambda to pass the difficulty name into set_difficulty().
  • Add Restart and Quit menu actions.
  • Build a Help menu with an About action.

🎓 Core Concepts

Tkinter menus: A menu bar (tk.Menu) attaches to the main window. Inside it, you create sub-menus (like “Game” and “Help”) and add commands.

Callbacks (what happens when you click): When you add a command, you pass a function without calling it. For example, command=self.reset_board is correct (no parentheses). Tkinter will call it later when the user clicks.

Passing data with lambda: We want each difficulty option to call set_difficulty() with a specific name. If we wrote command=self.set_difficulty(name) inside the loop, it would run immediately while building the menu. Instead we use:

lambda n=name: self.set_difficulty(n)

That creates a tiny “wrapper function” that remembers the current name for that menu item.

Wiring UI actions to model changes: The menu doesn’t change the board directly. It calls app methods (like set_difficulty() and reset_board()), and those methods will handle updating the board and UI in later sections.

💻 Code to Write (inside class GameApp in app.py)

Type this by hand so you understand each piece.

Code image: s09-code

🧠 Code Review & Key Concepts

menubar = tk.Menu(self) creates the top-level menu bar attached to the window.

tk.Menu(menubar, tearoff=False) makes a submenu. tearoff=False disables the dashed “tear off” line (cleaner for students/users).

The for name in S.DIFFICULTIES: loop automatically creates one menu command per preset in settings.py. If you add a new preset later, it will show up here without more UI changes.

lambda n=name: ... is the key line: it captures the current value of name so each menu item calls set_difficulty() with the correct difficulty.

self.config(menu=menubar) attaches the menu bar to the window so it appears at the top.

🧪 Test File (create s9_test.py)

Code image: s09-test

This test checks that GameApp has the _make_menu() method. We don’t instantiate the Tkinter window here because the class still depends on methods like set_difficulty() and _show_about() that will be implemented in later sections.