[^] CTkTableFrame
[+] custom columns
This commit is contained in:
parent
89d664d2f9
commit
602ac4bcea
@ -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("<Double-1>", lambda event, r=row_data: self._callback(r))
|
||||
row_frame.bind("<Double-1>", 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("<Double-1>", lambda event, r=row_data: self._callback(r))
|
||||
cell_label.bind("<Double-1>", 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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user