
- •Введение
- •Анализ предметной области
- •Анализ сущностей и связей между ними
- •Составление запросов к базе данных и их инкапсуляция
- •Реализация пользователей и предоставление им прав
- •Реализация триггеров
- •Реализация пользовательского интерфейса
- •Заключение
- •Список использованных источников
- •Приложение а. Скриншоты заполненных таблиц
- •Приложение б. Код для создания базы данных
- •Приложение в. Код для создания графического интерфейса
Приложение в. Код для создания графического интерфейса
Листинг 18 – Код для создания графического интерфейса
import tkinter as tk
from tkinter import ttk, messagebox
import pymysql
from pymysql import MySQLError
import sv_ttk
import matplotlib.pyplot as plt
import pandas as pd
def center_window(width=900, height=600):
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
x = (screen_width/2) - (width/2)
y = (screen_height/2) - (height/2)
root.geometry('%dx%d+%d+%d' % (width, height, x, y))
def connect_to_database(host, database, user, password):
""" Подключение к базе данных MySQL """
try:
connection = pymysql.connect(
host=host,
database=database,
user=user,
password=password,
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor
)
root.title(f"{user}")
messagebox.showinfo("Успех", "Успешное подключение к базе данных")
return connection
except MySQLError as e:
messagebox.showerror("Ошибка", f"Ошибка подключения к базе данных: {e}")
return None
def get_stored_procedures(connection):
""" Получение списка хранимых процедур """
try:
with connection.cursor() as cursor:
cursor.execute("SHOW PROCEDURE STATUS WHERE Db = DATABASE()")
procedures = cursor.fetchall()
return [proc['Name'] for proc in procedures]
except MySQLError as e:
messagebox.showerror("Ошибка", f"Ошибка получения процедур: {e}")
return []
def get_tables(connection):
""" Получение списка таблиц """
try:
with connection.cursor() as cursor:
cursor.execute("SHOW TABLES")
tables = cursor.fetchall()
return [list(table.values())[0] for table in tables]
except MySQLError as e:
messagebox.showerror("Ошибка", f"Ошибка получения таблиц: {e}")
return []
def get_procedure_parameters(connection, procedure_name):
""" Получение списка параметров процедуры """
try:
with connection.cursor() as cursor:
cursor.execute(f"""
SELECT PARAMETER_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.PARAMETERS
WHERE SPECIFIC_NAME = '{procedure_name}'
ORDER BY ORDINAL_POSITION
""")
parameters = cursor.fetchall()
return parameters
except MySQLError as e:
messagebox.showerror("Ошибка", f"Ошибка получения параметров процедуры: {e}")
return []
def view_table(connection, table_name):
""" Просмотр содержимого таблицы """
try:
cursor = connection.cursor()
cursor.execute(f"SELECT * FROM {table_name}")
results = cursor.fetchall()
cursor.close()
return results
except MySQLError as e:
messagebox.showerror("Ошибка", f"Ошибка просмотра таблицы: {e}")
return None
def call_procedure(connection, procedure_name, args):
""" Выполнение процедуры и вывод результата """
try:
cursor = connection.cursor()
cursor.callproc(procedure_name, args)
results = cursor.fetchall()
cursor.close()
return results
except MySQLError as e:
messagebox.showerror("Ошибка", f"Ошибка выполнения процедуры: {e}")
return None
def show_procedure_screen():
""" Переход на экран выбора процедуры """
global procedures, tables
procedures = get_stored_procedures(connection)
tables = get_tables(connection)
procedure_combobox['values'] = procedures
table_combobox['values'] = tables
connection_frame.pack_forget()
procedure_frame.pack()
def execute_procedure():
procedure_name = procedure_combobox.get()
if not procedure_name:
messagebox.showwarning("Внимание", "Пожалуйста, выберите процедуру")
return
args = [entry.get() for entry in arg_entries]
results = call_procedure(connection, procedure_name, args)
display_results(results)
edit_button.grid_remove()
add_button.grid_remove()
def view_selected_table():
table_name = table_combobox.get()
if not table_name:
messagebox.showwarning("Внимание", "Пожалуйста, выберите таблицу")
return
results = view_table(connection, table_name)
display_results(results)
edit_button.grid(row=8, columnspan=2, sticky="w", pady=10)
add_button.grid(row=8, column=1, columnspan=2, sticky="e", pady=10)
def display_results(results):
if results:
for col in treeview['columns']:
treeview.heading(col, text='')
treeview.delete(*treeview.get_children())
columns = list(results[0].keys())
treeview['columns'] = columns
for col in columns:
treeview.heading(col, text=col)
treeview.column(col, width=60)
for row in results:
treeview.insert('', 'end', values=[row[col] for col in columns])
def connect():
global connection
host = host_entry.get()
database = database_entry.get()
user = user_entry.get()
password = password_entry.get()
connection = connect_to_database(host, database, user, password)
if connection:
show_procedure_screen()
def on_procedure_select(event):
procedure_name = procedure_combobox.get()
parameters = get_procedure_parameters(connection, procedure_name)
for widget in arg_frame.winfo_children():
widget.destroy()
global arg_entries
arg_entries = []
for param in parameters:
ttk.Label(arg_frame, text=param['PARAMETER_NAME']).pack()
entry = ttk.Entry(arg_frame)
entry.pack()
arg_entries.append(entry)
def edit_selected_row():
selected_item = treeview.selection()
if not selected_item:
messagebox.showwarning("Внимание", "Пожалуйста, выберите запись для редактирования")
return
selected_item = selected_item[0]
selected_data = treeview.item(selected_item, 'values')
columns = treeview['columns']
selected_data = selected_data[1:]
columns = columns[1:]
edit_window = tk.Toplevel(root)
edit_window.title("Редактирование записи")
entries = []
for i, col in enumerate(columns):
ttk.Label(edit_window, text=col).grid(row=i, column=0, pady=10, padx=10)
entry = ttk.Entry(edit_window)
entry.insert(0, selected_data[i])
entry.grid(row=i, column=1, pady=10, padx=10)
entries.append(entry)
def save_changes():
new_data=[]
entry_list = [entry.get() for entry in entries]
new_columns = []
old_data = []
for i, entry in enumerate(entry_list):
if entry not in list(selected_data):
new_data.append(entry)
new_columns.append(columns[i])
old_data.append(list(selected_data)[i])
edited_columns = ()
for column in new_columns:
print(column)
edited_columns = edited_columns + tuple([column])
#new_data = [entry.get() for entry in entries]
update_table(connection, table_combobox.get(), edited_columns, old_data, new_data)
view_selected_table()
edit_window.destroy()
ttk.Button(edit_window, text="Сохранить", command=save_changes).grid(row=len(columns), columnspan=2)
def update_table(connection, table_name, columns, old_data, new_data):
try:
cursor = connection.cursor()
set_clause = ', '.join([f"{col}=%s" for col in columns])
where_clause = ' AND '.join([f"{col}=%s" for col in columns])
query = f"UPDATE {table_name} SET {set_clause} WHERE {where_clause}"
print(new_data + old_data)
print(query)
cursor.execute(query, new_data + old_data)
connection.commit()
cursor.close()
messagebox.showinfo("Успех", "Запись успешно обновлена")
except MySQLError as e:
messagebox.showerror("Ошибка", f"Ошибка обновления записи: {e}")
def add_new_row():
table_name = table_combobox.get()
if not table_name:
messagebox.showwarning("Внимание", "Пожалуйста, выберите таблицу")
return
columns = treeview['columns']
columns = columns[1:]
add_window = tk.Toplevel(root)
add_window.title("Добавление новой записи")
entries = []
for i, col in enumerate(columns):
ttk.Label(add_window, text=col).grid(row=i, column=0, pady=10, padx=10)
entry = ttk.Entry(add_window)
entry.grid(row=i, column=1, pady=10, padx=10)
entries.append(entry)
def save_new_row():
new_data = [entry.get() for entry in entries]
insert_into_table(connection, table_name, columns, new_data)
view_selected_table()
add_window.destroy()
ttk.Button(add_window, text="Добавить", command=save_new_row).grid(row=len(columns), columnspan=2, pady=10, padx=10)
def insert_into_table(connection, table_name, columns, new_data):
try:
cursor = connection.cursor()
columns_str = ', '.join(columns)
values_str = ', '.join(['%s'] * len(columns))
query = f"INSERT INTO {table_name} ({columns_str}) VALUES ({values_str})"
cursor.execute(query, new_data)
connection.commit()
cursor.close()
messagebox.showinfo("Успех", "Запись успешно добавлена")
except MySQLError as e:
messagebox.showerror("Ошибка", f"Ошибка добавления записи: {e}")
def graph_pie():
plt.figure()
args = ""
results = call_procedure(connection, "GetCustomerTotalValue", args)
df_pie = pd.DataFrame(results)
def make_autopct(values):
def my_autopct(pct):
total = float(sum(values))
val = int(round(pct*total/100.0))
return '{p:.0f}% ({v:d})'.format(p=pct,v=val)
return my_autopct
plt.pie(df_pie["total_value"], labels=df_pie["customer_name"], autopct=make_autopct(df_pie["total_value"]))
plt.textprops={'size': 'x-large'}
plt.title('5 самых денежных заказчиков')
def graph_plot():
plt.figure()
args = ""
results = call_procedure(connection, "get_customer_count_for_top_shows", args)
df_plot = pd.DataFrame(results)
plt.plot(df_plot["rating"], df_plot["customer_count"], color='b', marker='.')
plt.grid()
plt.xlabel("Рейтинг")
plt.ylabel("Количество клиентов")
plt.title('Количество клиентов по рейтингу шоу')
def graph_hist():
args = ""
results = call_procedure(connection, "get_ad_count_weekday", args)
df_hist = pd.DataFrame(results)
fig, ax = plt.subplots()
bars = plt.bar(df_hist["weekday"],df_hist["advertisements_count"])
ax.bar_label(bars)
ax.spines[['right', 'top']].set_visible(False)
plt.title('Количество рекламы с 13 до 17 по будням')
def show_graphs():
graph_pie()
graph_plot()
graph_hist()
plt.show()
# Создание графического интерфейса
root = tk.Tk()
root.title("Рекламная компания на телевидении")
center_window(1200, 650)
sv_ttk.set_theme("dark")
# Экран подключения
connection_frame = ttk.Frame(root)
ttk.Label(connection_frame, text="Хост:").grid(row=0, column=0, sticky="w", pady=10, padx=10)
host_entry = ttk.Entry(connection_frame)
host_entry.grid(row=0, column=1, pady=10, padx=10)
host_entry.insert(0, "localhost")
ttk.Label(connection_frame, text="База данных:").grid(row=1, column=0, sticky="w", pady=10, padx=10)
database_entry = ttk.Entry(connection_frame)
database_entry.grid(row=1, column=1, pady=10, padx=10)
database_entry.insert(0, "tv_advertising_company")
ttk.Label(connection_frame, text="Пользователь:").grid(row=2, column=0, sticky="w", pady=10, padx=10)
user_entry = ttk.Entry(connection_frame)
user_entry.grid(row=2, column=1, pady=10, padx=10)
#user_entry.insert(0, "administrator")
ttk.Label(connection_frame, text="Пароль:").grid(row=3, column=0, sticky="w", pady=10, padx=10)
password_entry = ttk.Entry(connection_frame, show='*')
password_entry.grid(row=3, column=1, pady=10, padx=10)
#password_entry.insert(0, "administrator")
connect_button = ttk.Button(connection_frame, text="Подключиться", command=connect)
connect_button.grid(row=4, columnspan=2, pady=10, padx=10)
connection_frame.pack()
# Экран выбора процедуры и таблицы
procedure_frame = ttk.Frame(root)
graphs_button = ttk.Button(procedure_frame, text="Показать графики", command=show_graphs)
graphs_button.grid(row=0, columnspan=2, pady=10)
ttk.Label(procedure_frame, text="Выберите процедуру:").grid(row=1, column=0, pady=10, padx=10)
procedure_combobox = ttk.Combobox(procedure_frame)
procedure_combobox.grid(row=1, column=1, pady=10, padx=10)
procedure_combobox.bind("<<ComboboxSelected>>", on_procedure_select)
execute_button = ttk.Button(procedure_frame, text="Выполнить процедуру", command=execute_procedure)
execute_button.grid(row=1, column=3, columnspan=4, pady=10, padx=10)
arg_frame = ttk.Frame(procedure_frame)
arg_frame.grid(row=3, columnspan=2, pady=10, padx=10)
ttk.Label(procedure_frame, text="Выберите таблицу:").grid(row=4, column=0, pady=10, padx=10)
table_combobox = ttk.Combobox(procedure_frame)
table_combobox.grid(row=4, column=1, pady=10, padx=10)
view_table_button = ttk.Button(procedure_frame, text="Просмотреть таблицу", command=view_selected_table)
view_table_button.grid(row=4, column=3, columnspan=4, pady=10, padx=10)
treeview = ttk.Treeview(procedure_frame, show='headings')
treeview.grid(row=6, columnspan=4, sticky='nsew', pady=10, padx=10)
scrollbar_x = ttk.Scrollbar(procedure_frame, orient='horizontal', command=treeview.xview)
scrollbar_x.grid(row=7, columnspan=4, sticky='ew', pady=10, padx=10)
treeview.configure(xscrollcommand=scrollbar_x.set)
scrollbar_y = ttk.Scrollbar(procedure_frame, orient='vertical', command=treeview.yview)
scrollbar_y.grid(row=6, column=4, sticky='ns', pady=10, padx=10)
treeview.configure(yscrollcommand=scrollbar_y.set)
# Кнопка редактирования
edit_button = ttk.Button(procedure_frame, text="Редактировать запись", command=edit_selected_row)
add_button = ttk.Button(procedure_frame, text="Добавить запись", command=add_new_row)
procedure_frame.pack_forget()
root.mainloop()
# Закрытие соединения с базой данных при выходе из программы
if 'connection' in globals() and connection:
connection.close()