105 lines
4.9 KiB
Python
105 lines
4.9 KiB
Python
import customtkinter as ctk
|
||
|
||
class CTkTableFrame(ctk.CTkFrame):
|
||
def __init__(self, master: ctk.CTk | ctk.CTkToplevel, 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)
|
||
|
||
def _create_table(self):
|
||
event.call("loading.open")
|
||
event.call("loading.set_progress", 0)
|
||
event.call("loading.set_text", "Таблица")
|
||
|
||
event.call("loading.set_subtext", "очистка")
|
||
"""Создает таблицу с заголовками и данными, используя параметры из словаря."""
|
||
_old_children = self.winfo_children()
|
||
for i, widget in enumerate(_old_children):
|
||
widget.destroy()
|
||
event.call("loading.set_progress", (i + 1) / len(_old_children))
|
||
|
||
scroll_frame = ctk.CTkScrollableFrame(self)
|
||
event.call("loading.set_progress", 0)
|
||
event.call("loading.set_subtext", "настройка")
|
||
_need_to_pack = []
|
||
|
||
# Применяем шаблон значений по умолчанию
|
||
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]
|
||
for col in self.columns:
|
||
if type(col) == dict:
|
||
if "width" not in col:
|
||
col["width"] = (len(col["name"]) * 7) + 14
|
||
columns.append({**default_column, **col})
|
||
else:
|
||
columns.append({**default_column, "width": (len(col) * 7) + 14, "name": col})
|
||
|
||
print(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"])
|
||
|
||
event.call("loading.set_progress", 1)
|
||
# Заголовки
|
||
header_frame = ctk.CTkFrame(scroll_frame, fg_color="gray30")
|
||
_need_to_pack.append((header_frame, {"fill": "x", "padx": 2, "pady": 1}))
|
||
|
||
for col in columns:
|
||
header_label = ctk.CTkLabel(
|
||
header_frame, text=col["name"], width=col["width"], anchor=col["align"], padx=5
|
||
)
|
||
_need_to_pack.append((header_label, {"side": "left", "padx": 2, "pady": 3}))
|
||
|
||
event.call("loading.set_progress", 0)
|
||
event.call("loading.set_subtext", "подготовка данных")
|
||
# Данные
|
||
for row_index, row_data in enumerate(self.data):
|
||
row_frame = ctk.CTkFrame(scroll_frame, fg_color="gray20", corner_radius=3, height=20)
|
||
_need_to_pack.append((row_frame, {"fill": "x", "padx": 2, "pady": 1}))
|
||
if self._callback:
|
||
row_frame.bind("<Double-1>", lambda event, idx=row_index, r=row_data: self._callback({"row_index": idx, "row_data": r}))
|
||
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)
|
||
_need_to_pack.append((cell_label, {"side": "left", "padx": 2, "pady": 2}))
|
||
if self._callback:
|
||
cell_label.bind("<Double-1>", lambda event, idx=row_index, r=row_data: self._callback({"row_index": idx, "row_data": r}))
|
||
|
||
if row_index % 2 == 0:
|
||
event.call("loading.set_progress", (row_index + 1) / len(self.data))
|
||
|
||
event.call("loading.set_progress", 0)
|
||
event.call("loading.set_subtext", "отрисовка данных")
|
||
for i, (widget, pack_params) in enumerate(_need_to_pack):
|
||
if i % 2 == 0:
|
||
event.call("loading.set_progress", (i + 1) / len(_need_to_pack))
|
||
widget.pack(**pack_params)
|
||
scroll_frame.pack(fill="both", expand=True, padx=5, pady=5)
|
||
event.call("loading.close")
|
||
|
||
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()
|