Содержание:
- 1. Программа в действии
- 2. Работа над Frontend файлом
- 3. Работа над Backend файлом
- 4. Коннект фронтенда с бэкендом
-
Приложение создано с использованием GUI библиотеки Tkinter и библиотеки SQLite для работы с базой данных.
-
Приложение имеет 4 текстовых поля для ввода данных о книге (Название, Автор, Год и ISBN уникальный идентификационный номер) и сохранения их в базе.
-
С помощью кнопок приложения, пользователь может добавить новую книгу в базу, изменить данные о книге, найти книгу по одному из четырех параметров и вывести информацию на экран, посмотреть все записи о книгах, удалить запись.
-
В программе также реализован объектно-ориенированный подход. Код программы с использованием методов ООП см. в файле: bookstore/frontend_oop.py и bookstore/backend_oop.py.
- Кнопка View all - выводит все записи в окно.
- Кнопка Search entry - производит поиск по любому из 4-х параметров и выводит результат в окно.
- Кнопка Add entry - добавляет запись о книге в базу данных.
- Кнопка Update selected - редактирует запись.
- Кнопка Delete selected - удаляет запись.
- Кнопка Close закрывает окно.
Начнем с создания Frontend файла. Создадим графический пользовательский интерфейс: главное окно, кнопки, поля ввода, скроллер, которые пока не будут выполнять никаких действий.
- Полный код см. в файле bookstore/frontend.py
window = Tk()
window.mainloop()
- Метки:
l1=Label(window,text="Title")
l1.grid(row=0,column=0) # используем метод grid
- Текстовые поля ввода:
title_text = StringVar()
e1 = Entry(window, textvariable=title_text)
e1.grid(row=0,column=1)
- Список (Listbox):
list1 = Listbox(window, height=6, width=35)
list1.grid(column=0, row=2,rowspan=6,columnspan=2)
- Скроллер:
sb1 = ttk.Scrollbar(window, orient=VERTICAL, command=list1.yview)
sb1.grid(column=2, row=2,rowspan=6)
list1.configure(yscrollcommand=sb1.set) # применение метода configure к списку listbox
sb1.configure(command=list1.yview)
- Кнопки:
b1 = Button(window, text='View all', width=12)
b1.grid(row=2,column=3)
Создадим Backend файл с функциями просмотра, поиска, добавления, удаления, редактирования записей. То есть, определим функции для каждой из созданных кнопок. Задействуем бибилиотеку SQLite3 для работы с базой данных и вызова данных на наш пользовательский интерфейс.
- Полный код см. в файле bookstore/backend.py
def connect():
conn = sqlite3.connect("books.db")
cur = conn.cursor()
cur.execute("CREATE TABLE IF NOT EXISTS book (id INTEGER PRIMARY KEY, title text, author text, year integer, isbn integer)")
conn.commit()
conn.close()
def insert(title, author, year, isbn):
cur = conn.cursor()
cur.execute("INSERT INTO book VALUES (NULL, ?, ?, ?, ?)",(title, author, year, isbn))
** NULL означает, что id будет создан автоматически.
** 4 знака ? для каждого из аргументов функции.
** Далее передаем параметры (title, author, year, isbn) в качестве второго параметра функции execute.
def view():
cur.execute("SELECT * FROM book")
def search(title="", author="", year="", isbn=""):
conn = sqlite3.connect("books.db")
cur = conn.cursor()
cur.execute("SELECT * FROM book WHERE title=? OR author=? OR year=? OR isbn=?",(title, author, year, isbn))
rows = cur.fetchall()
conn.close()
return rows
** Задействован OR поиск. Это значит, что пользователь может ввести имя автора, год, назавание, или номер книги (title, author, year, isbn), либо все параметры вместе. Допустим, если введен только год написания, то будут показаны все книги, вышедшие в указанном году.
** (title="", author="", year="", isbn="") Пустые строки в качестве значений нужны, чтобы не возникала ошибка в случае, если будет введен аргумент только для одного из параметров, а оставшиеся параметры останутся без значений.
def delete(id):
** Функция принимает id в качестве параметра для удаления из базы данных строки с данным id.
def update(id, title, author, year, isbn):
def exists(title="", author="", year="", isbn=""):
cur.execute("SELECT * FROM book WHERE title=? AND author=? AND year=? AND isbn=?",(title, author, year, isbn))
** Функция такая же, как и функция search, только вместо OR поиска задействован AND поиск.
Связываем Фронтенд с Бэкендом
- Полный код см. в файле bookstore/frontend.py
b1 = Button(window, text='View all', width=12, command=view_command)
b1.grid(row=2,column=3)
** Функция view_command нужна чтобы получать данные функции view файла backend.py и вставлять эти данные в список Listbox в GUI.
- Используем цикл for для итерации списка кортежей и вывода их в качестве строк в Listbox:
def view_command():
list1.delete(0, END) # удаляет все записи из Listbox прежде чем выводить данные
for row in backend.view():
list1.insert(END, row)
def search_command():
list1.delete(0, END)
for row in backend.search(title_text.get(), author_text.get(), year_text.get(), isbn_text.get()):
list1.insert(END, row)
** Параметры для функции search берем из виджетов текстовых полей ввода.
** Метод .get() нужен так как title_text или author_text типы данных StringVar(), а не просто строка.
def add_command():
backend.insert(title_text.get(), author_text.get(), year_text.get(), isbn_text.get())
list1.delete(0, END)
list1.insert(END, (title_text.get(), author_text.get(), year_text.get(), isbn_text.get()))
-
Функция delete принимает id в качестве аргумента и удаляет строку с соответсвующим id из базы данных.
-
Соответсвенно, когда пользователь выбирает одну из строк в списке Listbox, мы должны получить id выбранной строки и передать его параметром в функцию delete файла backend.py.
list1.bind('<>', get_selected_row)
Метод bind привязывает функцию к виджету Listbox
- Далее определим функцию get_selected_row в начале скрипта.
def get_selected_row(event):
try:
global selected_tuple # глобальная переменная для использования в функции delete_command
index=list1.curselection()[0] # получаем индекс выбранной строки
selected_tuple=list1.get(index) # получаем кортеж со значениями строки
- Передадим id выбранного кортежа/строки в функцию delete файла backend.py.
def delete_command():
backend.delete(selected_tuple[0])
- Для заполнения текстовых полей элементами кортежа, используем функцию insert виджета entry.
e1.delete(0,END) # удаляет данные из текстового поля
e1.insert(END,selected_tuple[1]) # selected_tuple[1] - соответсвенно название книги
e2.delete(0,END)
e2.insert(END,selected_tuple[2]) # selected_tuple[2] - автор книги
- Функция get_selected_row теперь выглядит так:
def get_selected_row(event):
try:
global selected_tuple
index=list1.curselection()[0]
selected_tuple=list1.get(index)
e1.delete(0,END)
e1.insert(END,selected_tuple[1])
e2.delete(0,END)
e2.insert(END,selected_tuple[2])
e3.delete(0,END)
e3.insert(END,selected_tuple[3])
e4.delete(0,END)
e4.insert(END,selected_tuple[4])
except IndexError:
pass
** Обработка исключений try except нужна, чтобы не возникала ошибка IndexError, в случае, если пользователь кликнет по пустому списку Listbox.
def update_command():
if len(exists_command())>0:
list1.delete(0,END)
list1.insert(END,"ERROR! :: Book Already Exists")
else:
backend.update(selected_tuple[0], title_text.get(), author_text.get(), year_text.get(), isbn_text.get())
** if else оператор нужен на случай если книга уже находится в базе. Будет выдана ошибка: Такая книга уже есть!
b6 = Button(window, text='Close', width=12, command=window.destroy)