diff --git a/frames/CTkTableFrame.py b/frames/CTkTableFrame.py index 4c2e27d..2ff9b18 100644 --- a/frames/CTkTableFrame.py +++ b/frames/CTkTableFrame.py @@ -1,14 +1,10 @@ import customtkinter as ctk -from ..utils import fonts - - class CTkTableFrame(ctk.CTkFrame): - def __init__(self, master: ctk.CTk, columns, data, callback, width=400, height=200, *args, **kwargs): + def __init__(self, master: ctk.CTk, columns, data: list, callback, width=400, height=200, *args, **kwargs): super().__init__(master, *args, **kwargs) self.columns = columns self.data = data - self._callback = callback self.configure(width=width, height=height) @@ -19,35 +15,70 @@ class CTkTableFrame(ctk.CTkFrame): self._create_table() def _create_table(self): + """Создает таблицу с заголовками и данными, используя параметры из словаря.""" + for widget in self.scroll_frame.winfo_children(): + widget.destroy() + + # Применяем шаблон значений по умолчанию + default_column = {"width": 0, "align": "left", "name": "N/A"} + columns = [{**default_column, **col} if type(col) == dict else {**default_column, "name": col} for col in self.columns] + + # Функция преобразования align в формат anchor + def parse_align(align): + return {"left": "w", "right": "e", "center": "center"}.get(align, "w") + + # Определяем ширины: если текущая ширина меньше вычисленной, то обновляем + for i, col in enumerate(columns): + max_data_width = max((len(str(row[i])) * 7 for row in self.data if i < len(row)), default=0) + 10 + if col["width"] < max_data_width: + col["width"] = max_data_width + col["align"] = parse_align(col["align"]) + # Заголовки header_frame = ctk.CTkFrame(self.scroll_frame, fg_color="gray30") header_frame.pack(fill="x", padx=2, pady=1) - for col in self.columns: - header_label = ctk.CTkLabel(header_frame, text=col, font=fonts.body_med_font(), padx=5) - header_label.pack(side="left", padx=5, pady=3, expand=True) + for col in columns: + header_label = ctk.CTkLabel( + header_frame, text=col["name"], width=col["width"], anchor=col["align"], padx=5 + ) + header_label.pack(side="left", padx=2, pady=3) # Данные - for row_data in self.data: + for row_index, row_data in enumerate(self.data): row_frame = ctk.CTkFrame(self.scroll_frame, fg_color="gray20", corner_radius=3, height=20) row_frame.pack(fill="x", padx=2, pady=1) - # Обработчик двойного клика - row_frame.bind("", lambda event, r=row_data: self._callback(r)) + row_frame.bind("", lambda event, idx=row_index, r=row_data: self._callback({"row_index": idx, "row_data": r})) - for cell in row_data: - cell_label = ctk.CTkLabel(row_frame, text=cell, font=fonts.small_font(), padx=5) - cell_label.pack(side="left", padx=5, pady=2, expand=True) + for i, col in enumerate(columns): + cell_text = str(row_data[i]) if i < len(row_data) else "" + cell_label = ctk.CTkLabel(row_frame, text=cell_text, width=col["width"], anchor=col["align"], padx=5) + cell_label.pack(side="left", padx=2, pady=2) - # Прокидываем клик от ячеек на строку - cell_label.bind("", lambda event, r=row_data: self._callback(r)) + cell_label.bind("", lambda event, idx=row_index, r=row_data: self._callback({"row_index": idx, "row_data": r})) + def edit(self, row_index, new_data): + """Редактирует строку по индексу.""" + if 0 <= row_index < len(self.data): + self.data[row_index] = new_data + self.redraw() + + def add(self, new_data): + """Добавляет новую строку.""" + self.data.append(new_data) + self.redraw() + + def redraw(self): + """Перерисовывает таблицу.""" + self._create_table() # Пример использования if __name__ == "__main__": + from utils import fonts app = ctk.CTk() - app.geometry("600x400") + app.geometry("800x400") def show_modal(row_data): modal = ctk.CTkToplevel(app) @@ -67,13 +98,20 @@ if __name__ == "__main__": ctk.set_appearance_mode("dark") - columns = ["ID", "Имя", "Логин"] - data = [(i, f"Имя {i}", f"i1111-{i}") for i in range(1, 21)] # 20 строк для теста скролла + # _table_columns = [(0, "C", "ID"), (100, "Имя"), (100, "Логин"), (100, "Пароль"), (100, "Права"), (150, "Статус")] + _table_columns = [{"align": "center", "name": "ID"}, "Имя", "Логин", "Пароль", "Права", "Статус"] + _table_data = [ + (1, "Master Admin", "admin", "*********", "Админ", "Активен"), + (2, "Первая стоматология Авиаконструкторов", "i00001608", "i00001608", "Доктор", "Заблокирован"), + (3, "Dental Lounge Ester", "i00151889", "*********", "Доктор", "Активен"), + *[(i, f"Имя {i}", f"i0015188{i}", f"i0015188{i}", "Доктор", "Активен") for i in range(4, 11)] + ] lable = ctk.CTkLabel(app, text="Тестовая таблица", font=fonts.title_font()) lable.pack(pady=10) - table = CTkTableFrame(app, columns, data, show_modal, width=400, height=200) + table = CTkTableFrame(app, _table_columns, _table_data, show_modal, width=700, height=200) + table.add((10000, "1", 1, "111111111111111111")) table.pack(pady=10, padx=20, fill="both", expand=True) but1 = ctk.CTkButton(app, text="Закрыть", command=app.destroy)