Tkinter GUI for CRUD app #1

In the >>previous post<<, I described a simple CRUD program that modifies a database (SQLite in this case).

For the program I created earlier, I will create GUI in the tkinter library. The interface will be developed gradually, making it easier to explain the methods used.

Program code can be found here.

I will slightly modify the files created in the previous post, i.e. for the class Car() I’ll add a class method that creates an instance when from a list. In addition, in the Helper () class, the del_car () method, apart from deleting the car from the database, also deletes all data about the entered repairs related to this car. The code of the new fragments looks like this:

class Car():
    @classmethod
    def from_list(cls, list):
        make, model, year, vrn, vin, sold = list
        return cls(make, model, year, vrn, vin, sold)

class Helper():
    def del_car(self, car):
        with self.conn:
            self.c.execute("SELECT ROWID FROM cars WHERE vin=:vin",
                           {'vin': car.vin})
            car_id = self.c.fetchone()
            self.c.execute("DELETE FROM repairs WHERE car=?",
                           (car_id))
            self.c.execute("DELETE FROM cars WHERE vin=:vin", {'vin': car.vin})

Here is my CarManager() class describing the graphical interface.

import tkinter as tk
from tkinter import messagebox, ttk
from sql_helper import Helper
from car import Car

class CarManager(tk.Frame):
    def __init__(self, root):
        super().__init__(root)
        self.root = root
        self.helper = Helper()
        root.title('Car manager')
        root.iconphoto(True, tk.PhotoImage(file='Resources/car_logo.png'))
        root.bind('<Control-x>', self.close_app)
        root.columnconfigure(1, weight=1)
        root.rowconfigure(2, weight=1)
        self.create_widgets()
        self.show_cars()


if __name__ == '__main__':
    root = tk.Tk()
    cm = CarManager(root)
    cm.mainloop()

When creating an instance of the CarManager class, I create instance of the Helper class, set the name of the created window to ‘Car Manager’ and add the program icon from the Resources directory. In addition, I set a hotkey to end the program (Ctrl + x). Then I set the way the widgets are to be scaled when the window is resized.

The last two lines of the init () method run the methods responsible for creating all widgets in the main window and for displaying data from the database about the saved cars.

Here is my close_app () method:

    def close_app(self, event):
        result = tk.messagebox.askyesno('Exit', 'Close application?')
        if result:
            self.root.destroy()

The result is True when selected the close app button, the main application window is closed.

Code of my create_widgets () method responsible for displaying interface elements:

def create_widgets(self):
        # create menu
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)
        file_menu = tk.Menu(menubar, tearoff=0)
        file_menu.add_command(label='Exit', command=exit, accelerator="Ctrl+x")
        menubar.add_cascade(label="File", menu=file_menu)

        # create toolbar
        tbar_frame = tk.Frame(root, height=10)
        tbar_frame.grid(row=0, column=0)

        self.add_car_img = tk.PhotoImage(file='Resources/add_car.gif')
        self.remove_car_img = tk.PhotoImage(file='Resources/remove_car.gif')
        self.repairs_img = tk.PhotoImage(file='Resources/repairs.gif')
        self.sold_img = tk.PhotoImage(file='Resources/sold.gif')

        add_car_button = tk.Button(tbar_frame, image=self.add_car_img,
                                   command=self.add_car).grid(row=0, column=0, sticky='W')
        del_car_button = tk.Button(tbar_frame, image=self.remove_car_img,
                                   command=self.del_car).grid(row=0, column=0, sticky='W', padx=30)
        repairs_button = tk.Button(tbar_frame, image=self.repairs_img,
                                   command=self.show_repairs).grid(row=0, column=0, sticky='W', padx=60)
        sold_button = tk.Button(tbar_frame, image=self.sold_img,
                                command=self.sell_car).grid(row=0, column=0, sticky='W', padx=90)

        # create search entry
        self.search_variable = tk.StringVar()
        self.search_entry = tk.Entry(
            root, textvariable=self.search_variable)
        self.search_entry.config(fg='grey')
        self.search_variable.set("Search car by VRN")
        self.search_entry.bind('<FocusIn>', self.on_entry_in)
        self.search_entry.bind('<FocusOut>', self.on_entry_out)
        self.search_entry.bind('<Return>', self.on_entry_return)
        self.search_entry.bind('<KP_Enter>', self.on_entry_return)
        self.search_entry.grid(row=0, column=1, sticky='E', ipadx=20)

        # create TreeView with Scrollbar
        col_headers = ('No', 'Make', 'Model', 'Year', 'VRN', 'VIN', 'Sold')
        self.car_tview = ttk.Treeview(self.root, columns=col_headers,
                                      show='headings', selectmode='browse')
        self.car_tview.columnconfigure(0, weight=1)
        self.car_tview.rowconfigure(0, weight=1)
        # set column headers
        for i, col in enumerate(col_headers):
            self.car_tview.heading(col, text=col)
            self.car_tview.column(col, anchor='center')
            if i == 0:
                self.car_tview.column(col, width=50, stretch='NO')
        self.car_tview.grid(row=2, column=0, columnspan=2, sticky='NSWE')

        scrollbar = tk.Scrollbar(self.root, command=self.car_tview.yview)
        scrollbar.grid(column=3, row=2, sticky='NS')
      

Successively, the program menu is created, then a toolbar with buttons for adding a car to the database, removing a car, adding data about car repairs and marking the sale of the car.

Then, a car search by the registration number field is created to which methods are attached to react to the events of obtaining / losing focus and confirming data by pressing the ENTER key on: numeric keypad (<KP_Enter>) or main keypad (<Return>).

The next few lines define a TreeView widget containing cars data and a scroll bar, if the data does not fit on the page.

After the changes, the main program window should look like this:

The initial window of the program. For now, no data …

Leave a Reply

Your email address will not be published. Required fields are marked *