Sunday, March 12, 2023

A Better MVC Example

Remember the last time I had posted about MVC(Python PyQt program and MySQL as a backend with a Model View Controller (MVC) design pattern)? That example was just really extremely simple and what I am thinking is what if I am working on a very large project? I want my program to be readable, extremely simplified and well organized.

My way of achieving this is to separate the the main program, model, view and controller modules into separate  files. Having it this way will reduce the size of the files I am going to edit and when it is small, it will be easier to navigate though the file and instantly hence, my productivity will increase. In post, I have created a small program that read the names of people stored in a sqlite3 database and displays the records on a QList Widget, when a name was clicked the contact details appreas on the QTextEdit widget on its righ right side.



Here is an example of the MVC I am talking about:

Introduction to the MVC Design Pattern

The Model-View-Controller (MVC) design pattern is a way of organizing code in a way that separates the user interface (View) from the underlying data (Model) and the code that manages the interaction between the two (Controller). This separation allows for easier maintenance and testing of code, and can lead to more flexible and modular applications.

The basic idea behind MVC is that the user interacts with the View, which then sends messages to the Controller, which in turn updates the Model. The Model can also send messages to the View to update the display. This way, the View and the Model are completely decoupled from each other, and only communicate through the Controller.

Construction of the Example Program

The example program provided is a simple application that displays a list of people in a database, and allows the user to select a person from the list to view their details.

The program is divided into three main components: the Model, the View, and the Controller.


Model

The Model component of the program is responsible for interacting with the database to retrieve and store data. In this program, the Model is implemented in the model.py file.


The Database class is defined in model.py. It creates a connection to a SQLite database and initializes a cursor to execute SQL commands. It also creates a table called people if it doesn't already exist, with columns for id, name, address, email, and phone.


The get_people method retrieves a list of names from the people table, and the get_person_details method retrieves the details for a specific person by name.


View

The View component of the program is responsible for displaying the user interface and interacting with the user. In this program, the View is implemented in the view.py file.


The View class is defined in view.py. It creates a QListWidget to display the list of names, and a QTextEdit to display the details of the selected person. These widgets are added to a QHBoxLayout, which is set as the layout for the View.


The set_names method takes a list of names and adds them to the QListWidget. The set_person_details method takes a tuple of details for a person and formats them into a string, which is then displayed in the QTextEdit.


Controller

The Controller component of the program is responsible for managing the interaction between the Model and the View. In this program, the Controller is implemented in the controller.py file.

The Controller class is defined in controller.py. It takes a Model and a View as arguments, and sets up the signals and slots for the interaction between the two.

The show_details method is called when the user selects a name from the QListWidget. It retrieves the details for the selected person from the Model, and then calls the set_person_details method on the View to update the display.

The initialize method is called when the Controller is created. It retrieves the list of names from the Model and calls the set_names method on the View to populate the QListWidget with the names.


Conclusion

In conclusion, the Model-View-Controller (MVC) design pattern is a powerful way to organize code in a way that separates concerns and makes code more modular and maintainable. The example program provided demonstrates how the MVC pattern can be used to create a simple application that displays data from a database. By separating the Model, View, and Controller components of the program, it becomes easier to test, maintain, and modify each part of the code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# Main
import sys
from model import Database 
from PyQt6.QtWidgets import QApplication
from view import View
from controller import Controller


if __name__ == "__main__":
    app = QApplication(sys.argv)

    # initialize model, view, and controller
    model = Database("mydatabase.db")
    view = View()
    controller = Controller(model, view)

    view.show()
    sys.exit(app.exec())

#model
import sqlite3

class Database:
    def __init__(self, db_name):
        self.connection = sqlite3.connect(db_name)
        self.cursor = self.connection.cursor()

        # create table if it doesn't exist
        self.cursor.execute("""CREATE TABLE IF NOT EXISTS people
                            (id INTEGER PRIMARY KEY,
                            name TEXT,
                            address TEXT,
                            email TEXT,
                            phone TEXT)""")
        self.connection.commit()

    def get_people(self):
        self.cursor.execute("SELECT name FROM people")
        return [row[0] for row in self.cursor.fetchall()]

    def get_person_details(self, name):
        self.cursor.execute("SELECT * FROM people WHERE name=?", (name,))
        return self.cursor.fetchone()

    def close(self):
        self.connection.close()

#controller
class Controller:
    def __init__(self, model, view):
        self.model = model
        self.view = view

        # connect signals and slots
        self.view.list_widget.itemClicked.connect(self.show_details)

        # initialize view with names from model
        self.view.set_names(self.model.get_people())

    def show_details(self, item):
        name = item.text()
        details = self.model.get_person_details(name)
        self.view.set_person_details(details)

#view
from PyQt6.QtWidgets import QListWidget, QTextEdit, QWidget, QHBoxLayout

class View(QWidget):
    def __init__(self):
        super().__init__()

        self.list_widget = QListWidget()
        self.list_widget.setFixedWidth(150)
        self.text_edit = QTextEdit()

        layout = QHBoxLayout()
        layout.addWidget(self.list_widget)
        layout.addWidget(self.text_edit)

        self.setLayout(layout)

    def set_names(self, names):
        self.list_widget.clear()
        self.list_widget.addItems(names)

    def set_person_details(self, details):
        if details:
            self.text_edit.setPlainText(f"Name: {details[1]}\n"
                                         f"Address: {details[2]}\n"
                                         f"Email: {details[3]}\n"
                                         f"Phone: {details[4]}")
        else:
            self.text_edit.clear()


No comments:

Post a Comment