The Model-View-Controller (MVC) pattern is a classic architecture that helps separate concerns in GUI applications. In this post, we’ll walk through how to build a simple counter app using Tkinter in Python, structured around the MVC pattern.
What We’re Building
A basic app with a number display and a button. Every time the button is clicked, the number increases by one.
Why Use MVC?
- Model: Manages the data and logic.
- View: Handles the GUI display.
- Controller: Connects user actions to updates in the Model and View.
Step 1: Create the Model
The Model stores the data and handles the logic. For our counter app, it just needs to store a number and increment it.
# model.py
class CounterModel:
def __init__(self):
self._count = 0
def increment(self):
self._count += 1
def get_count(self):
return self._count
Step 2: Create the View
The View is responsible for the user interface. It shows the current count and has a button the user can press.
# view.py
import tkinter as tk
class CounterView(tk.Tk):
def __init__(self):
super().__init__()
self.title("Simple MVC Counter")
self.label = tk.Label(self, text="0", font=("Arial", 24))
self.label.pack(pady=20)
self.button = tk.Button(self, text="Increment", font=("Arial", 14))
self.button.pack()
def set_controller(self, controller):
self.button.config(command=controller.increment_counter)
def update_count(self, count):
self.label.config(text=str(count))
Step 3: Create the Controller
The Controller acts as a bridge between the View and the Model. It handles the logic when the button is clicked.
# controller.py
from model import CounterModel
from view import CounterView
class CounterController:
def __init__(self, model, view):
self.model = model
self.view = view
self.view.set_controller(self)
def increment_counter(self):
self.model.increment()
new_count = self.model.get_count()
self.view.update_count(new_count)
Step 4: Hook Everything Together
Now, create a simple app.py
file to initialize the MVC components and start the app.
# app.py
from model import CounterModel
from view import CounterView
from controller import CounterController
def main():
model = CounterModel()
view = CounterView()
controller = CounterController(model, view)
view.mainloop()
if __name__ == "__main__":
main()
Step 5: Run
Make sure all files (model.py
, view.py
, controller.py
, and app.py
) are in the same directory. Then run:
python app.py
Step 6: Complete Code
# model.py
class CounterModel:
def __init__(self):
self._count = 0
def increment(self):
self._count += 1
def get_count(self):
return self._count
# view.py
import tkinter as tk
class CounterView(tk.Tk):
def __init__(self):
super().__init__()
self.title("Simple MVC Counter")
self.geometry("300x200")
self.label = tk.Label(self, text="0", font=("Arial", 24))
self.label.pack(pady=20)
self.button = tk.Button(self, text="Increment", font=("Arial", 14))
self.button.pack()
def set_controller(self, controller):
self.button.config(command=controller.increment_counter)
def update_count(self, count):
self.label.config(text=str(count))
# controller.py
class CounterController:
def __init__(self, model, view):
self.model = model
self.view = view
self.view.set_controller(self)
def increment_counter(self):
self.model.increment()
new_count = self.model.get_count()
self.view.update_count(new_count)
# app.py
def main():
model = CounterModel()
view = CounterView()
controller = CounterController(model, view)
view.mainloop()
if __name__ == "__main__":
main()