If you are stuggling to conceptualize how different classes and objects are interacting with each other, this example runs through a more simple demo of how to implment MVC using concepts you are familiar with like the turtle and input functions!
The project still requires you to use tkinter but running though this tutorial should give you a better handle on objects and classes communicating information between each other.
Below is a visualization of a basic Model-View-Controller Implementation
The following files are fully finished and should be ready to run if they are all in the correct place with the correct file names. Once you have finished setting up the application you can run it using python -m comp110.demos.mvc_tutorial
. We recommend you run the project and then read through the commented files to understand how it is built. Start with Controller.py
, then Model.py
, then View.py
and finally take a look at __main__.py
Build the project by creating a directory in comp110/demos
named mvc_tutorial
and then add the following code as specified.
Add a file in the mvc_tutorial
directory named Controller.py
"""This takes in user input from command line to control the turtle."""
# This is our controller, i.e. the part of the program that actively
# takes in user input. In this case, our input is just the terminal,
# we just use the input() function for this.
from typing import Set
from .Model import Model # Relative import for our Model
# We have a set of legal directions the user can move the turtle in
# we'll use it to validate that the terminal input is a legal
# direction.
DIRECTIONS: Set = {"up", "down", "left", "right"}
class Controller:
"""Controller class."""
model: Model # Holds the Model
running: bool # True if program is running, False if not
def __init__(self, model: Model):
"""Sets up controller, adds reference to model object, and begins reading user input."""
self.model = model
self.running = True
while self.running:
self.read_input() # Read user input repeatedly until running is false (more on that below.)
def read_input(self) -> None:
"""Responsible for validating user input and relaying it to the view (Player)."""
dir: str = str(input()) # User inputs a direction via the terminal
if dir == "quit":
self.running = False # set running to false, which will cause the while loop in __init__ to stop.
elif dir not in DIRECTIONS:
print("you typed an invalid command") # When user enters an invalid direction, print this message
# Note this won't exit the loop in __init__
else:
self.model.move(dir) # Now, having validated the direction, we can safely pass this to the Model.
Add a file in the mvc_tutorial
directory named Model.py
"""This is responsible for the 'game logic' or in our case the x and y coordinates."""
from .View import View
class Model:
"""Model class."""
x: int # This will help us keep track of where the turtle currently is on the screen.
y: int # We can reference these values in our View to create the visual
speed: int # This tells us how far to move the turtle in whatever direction the user specifies
view: View # Holds the view object
def __init__(self, speed: int, view: View):
"""Sets up the screen and the turtle's initial coordinates, along with the desired speed."""
self.x = 0
self.y = 0
self.speed = speed
self.view = view
def move(self, dir: str) -> None:
"""Moves the turtle in the specified direction."""
# Note that we've already validated that the user's direction is legal in the controller,
# so now we can just directly test against the four directions.
if dir == "up": # We know how much the turtle will move, so add/subtract
self.y += self.speed # from the x, y coordinates to represent where the turtle is going.
if dir == "down":
self.y -= self.speed
if dir == "right":
self.x += self.speed
if dir == "left":
self.x -= self.speed
# Once we have dealt with the game logic, we can pass our x and y to the view object
self.view.move(self.x, self.y)
Add a file in the mvc_tutorial
directory named View.py
"""This is responsible for drawing on the screen."""
# This is our View, i.e. the part of the program that interacts with
# the screen. The screen is just the turtle graphics window, similar
# to what you used in the first project.
from turtle import Turtle # Turtle is the OOP version of what we worked with in the past
# The functions you used in turtle all have method equivalents in the Turtle class
# ex. forward() == Turtle.forward() == t.forward() (t is our View Turtle)
class View:
"""View class."""
t: Turtle
def __init__(self):
"""Sets up the screen and the turtle."""
self.t = Turtle()
def move(self, x: int, y: int) -> None:
"""Moves the turtle to the specified coordinates."""
self.t.goto(x, y) # We recieve updated coordinates from the Model and can now update the view object
Add a file in the mvc_tutorial
directory named __main__.py
"""This brings together the View and Controller."""
from .View import View
from .Model import Model
from .Controller import Controller
print("Type up, down, left, right to move and quit to exit the program!")
view = View() # Set up the View object
model = Model(20, view) # Set up the Model object, specify speed, and pass it the instance of our view object
controller = Controller(model) # Set up the Controller object, and pass it the instance of our model object