I am goint to reorganize the code to use tkinter and sqlite using different windows made with tkinter for our program made with sqlite3 module in Python programming language to create a database… We are going to understand how to split the code into 4 different classes, so that we can have a clear understanding of who does what, when we will add other features to the program.
The new code
Last time we explained the menu window code you can see below:
import sqlite3 as lite from sqlite3 import Error import tkinter as tk from glob import glob class App: # window def __init__(self, root): self.root = root self.root.geometry("200x200") self.root['bg'] = "cyan" tk.Button(self.root, text = "Create a database", command= lambda: self.new_window(Win1)).pack() tk.Button(self.root, text = "Create a table", command= lambda: self.new_window(Win2)).pack() def new_window(self, _class): self.new = tk.Toplevel(self.root) _class(self.new)
I deleted the new_button function, as you can see in the video, because I thought it was nice but a little redundant, so, I prefer a little less code, even if it is a little less readable at first glance, but with the practice we won’t notice too much difference. If you want, you can always leave it like it was. See the code below to notice the difference and choose the best for you, it’s a matter of taste, after all.
self.butnew("Create Database", Win1) self.butnew("Create Table", Win2) def butnew(self, text, _class): tk.Button(self.root, text = text, command= lambda: self.new_window(_class)).pack()
Now it is:
tk.Button(self.root, text = "Create a database", command= lambda: self.new_window(Win1)).pack() tk.Button(self.root, text = "Create a table", command= lambda: self.new_window(Win2)).pack()
2 lines (splitted in 2) instead of 4 lines, wich one do you prefer? I like the first neat version, but the second avoids a method, so… let’s go on.
The mother of the new windows (super class)
In this class I want to put the common code that will be inherited by the other windows. For example we will put the listbox with the list of the database file that we create here, because we will use in window 1 and window 2 (Win1 and Win2 classes).
class Win: fields = [] # To create the records field in the databases table def listbox(self): self.lab_lb = tk.Label(self.root, text="Database in the folder") self.lab_lb.pack() self.lb = tk.Listbox(self.root) # create a listbox self.lb.pack() # make it visible for file in glob("*.db"): # insert all the db file in the listbox self.lb.insert(tk.END, file)
So, this class does nothing except contain the common attributes and methods of the windows.
Win1
Let’s see the Win1, to create the database:
class Win1(Win): def __init__(self, root): self.root = root self.root.geometry("400x300") self.root.title("Create Database") self.widgets_db() # widgets to create the new db self.listbox() def widgets_db(self): """Widgets to create a new database - a label "Create a db" ........ self.l - an entry ..................... self.e - a button ..................... self.b """ self.l = tk.Label(self.root, text="Create a db [insert the name]") self.l.pack() self.db = tk.StringVar() self.e = tk.Entry(self.root, textvariable = self.db) self.e.pack() self.b = tk.Button(self.root, text="Create DB", command= lambda: self.mk_db()) self.b.pack()
As you can see, this uses the listbox method of the super class Win and adds her own widgets to create the database (a label, an entry and a button).
We also need a method to create the database, that is the following one mk_db and it is used only in this window, so we add it to the Win1 class:
def mk_db(self): db = self.e.get() if db.endswith(".db"): pass else: db = db + ".db" try: conn = lite.connect(db) if db in self.lb.get(0, tk.END): pass else: self.lb.insert(tk.END, db) return conn except Error as e: print(e) finally: self.db.set("") conn.close()
Whatch the video to see how it works. There are a lot of lines, but it does a few basic things.
Win2
This is the second window. Until now it just has the listbox with the list of the database. So we do not need to write again the code for the listbox, we just need to call the method that has been inherited.
class Win2(Win): def __init__(self, root): self.root = root self.root.geometry("400x500") self.root.title("Create Tables") self.listbox()
There it is, just a listbox.
At the end, out of the classes there is the code to start it all, making the main window and istanciating the App class.
root = tk.Tk() app = App(root) root.mainloop()
The video with the live coding of the app until now
The whole code ’til now
This is the re-roganized code until now… we will continue in the next post.
import sqlite3 as lite from sqlite3 import Error import tkinter as tk from glob import glob class App: # window def __init__(self, root): self.root = root self.root.geometry("200x200") self.root['bg'] = "cyan" tk.Button(self.root, text = "Create a database", command= lambda: self.new_window(Win1)).pack() tk.Button(self.root, text = "Create a table", command= lambda: self.new_window(Win2)).pack() def new_window(self, _class): self.new = tk.Toplevel(self.root) _class(self.new) class Win: fields = [] # To create the records field in the databases table def listbox(self): self.lab_lb = tk.Label(self.root, text="Database in the folder") self.lab_lb.pack() self.lb = tk.Listbox(self.root) # create a listbox self.lb.pack() # make it visible for file in glob("*.db"): # insert all the db file in the listbox self.lb.insert(tk.END, file) class Win1(Win): def __init__(self, root): self.root = root self.root.geometry("400x300") self.root.title("Create Database") self.widgets_db() # widgets to create the new db self.listbox() def widgets_db(self): """Widgets to create a new database - a label "Create a db" ........ self.l - an entry ..................... self.e - a button ..................... self.b """ self.l = tk.Label(self.root, text="Create a db [insert the name]") self.l.pack() self.db = tk.StringVar() self.e = tk.Entry(self.root, textvariable = self.db) self.e.pack() self.b = tk.Button(self.root, text="Create DB", command= lambda: self.mk_db()) self.b.pack() def mk_db(self): db = self.e.get() if db.endswith(".db"): pass else: db = db + ".db" try: conn = lite.connect(db) if db in self.lb.get(0, tk.END): pass else: self.lb.insert(tk.END, db) return conn except Error as e: print(e) finally: self.db.set("") conn.close() class Win2(Win): def __init__(self, root): self.root = root self.root.geometry("400x500") self.root.title("Create Tables") self.listbox() root = tk.Tk() app = App(root) root.mainloop()
To be continued…