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._countStep 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.pyStep 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()