Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
19
Добавлен:
03.06.2024
Размер:
2.14 Mб
Скачать

Приложение в. Код для создания графического интерфейса

Листинг 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()