Загрузка данных


import tkinter as tk
from tkinter import ttk
from database import Database

class ProductsView:
    def __init__(self, parent, user):
        self.parent = parent
        self.user = user
        self.db = Database()

        # Главный контейнер страницы (встраивается в главное окно)
        self.window = tk.Frame(parent, bg="white")
        self.window.pack(fill=tk.BOTH, expand=True)

        tk.Label(self.window, text="Каталог товаров", font=("Arial", 14, "bold"), bg="white").pack(pady=10)

        # --- Создание скроллируемой области для ленты карточек ---
        container = tk.Frame(self.window, bg="white")
        container.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

        self.canvas = tk.Canvas(container, bg="white", highlightthickness=0)
        scrollbar = ttk.Scrollbar(container, orient=tk.VERTICAL, command=self.canvas.yview)
        
        # Фрейм внутри холста (Canvas), в котором вертикально будут упаковываться карточки
        self.scrollable_frame = tk.Frame(self.canvas, bg="white")
        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        )

        self.canvas_frame_id = self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        
        # Автоматически растягиваем карточки по всей доступной ширине окна
        self.canvas.bind('<Configure>', lambda event: self.canvas.itemconfigure(self.canvas_frame_id, width=event.width))
        self.canvas.configure(yscrollcommand=scrollbar.set)

        self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # Поддержка прокрутки колесиком мыши
        self.canvas.bind_all("<MouseWheel>", lambda event: self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units"))

        # Загружаем карточки товаров
        self.load_products_cards()

    def load_products_cards(self):
        # Очищаем старые карточки при обновлении страницы
        for widget in self.scrollable_frame.winfo_children():
            widget.destroy()

        products = self.db.get_all_products()

        for p in products:
            # Безопасное приведение типов данных для проверок
            try: discount = float(p.discount.replace('%', '').strip())
            except: discount = 0.0
            
            try: qty = float(p.quantity.strip())
            except: qty = 0.0

            # Подсветка карточек по цветам из Практики 5 (мягкие пастельные тона для читаемости текста)
            if qty == 0:
                bg_color = "#E3F2FD"      # Светло-голубой (нет на складе)
            elif discount > 10:
                bg_color = "#E8F5E9"      # Светло-зеленый (высокая скидка)
            else:
                bg_color = "white"        # Обычный белый цвет карточки

            # Создаем контейнер для ОДНОЙ карточки товара
            card_frame = tk.Frame(self.scrollable_frame, bg=bg_color, bd=1, relief=tk.SOLID)
            card_frame.pack(fill=tk.X, padx=10, pady=5, ipady=5)

            # ----------------------------------------------------
            # БЛОК 1 (ЛЕВЫЙ): Картинка товара
            # ----------------------------------------------------
            img_container = tk.Frame(card_frame, width=120, height=120, bg="white", bd=1, relief=tk.SOLID)
            img_container.pack(side=tk.LEFT, padx=15, pady=10)
            img_container.pack_propagate(False)

            try:
                # Пытаемся взять реальное имя фото товара, если пусто — берем picture.png
                img_file = p.photo if p.photo else "picture.png"
                img = tk.PhotoImage(file=img_file).subsample(2, 2) # Оптимизируем размер под список
                img_lbl = tk.Label(img_container, image=img, bg="white")
                img_lbl.image = img
                img_lbl.pack(fill=tk.BOTH, expand=True)
            except Exception:
                # Если файл картинки физически отсутствует в папке
                tk.Label(img_container, text="Нет фото", font=("Arial", 9, "italic"), bg="white", fg="gray").pack(fill=tk.BOTH, expand=True)

            # ----------------------------------------------------
            # БЛОК 2 (ЦЕНТРАЛЬНЫЙ): Текстовое описание товара
            # ----------------------------------------------------
            info_frame = tk.Frame(card_frame, bg=bg_color)
            info_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=15, pady=10)

            # Название товара
            tk.Label(info_frame, text=p.name, font=("Arial", 12, "bold"), bg=bg_color).pack(anchor=tk.W)
            
            # Описание (wraplength автоматически переносит длинный текст, чтобы он не улетал за экран)
            tk.Label(info_frame, text=f"Описание: {p.description}", font=("Arial", 9.5), bg=bg_color, fg="#333333", wraplength=500, justify=tk.LEFT).pack(anchor=tk.W, pady=3)
            
            # Производитель и Категория
            tk.Label(info_frame, text=f"Производитель: {p.manufacturer}   |   Категория: {p.category}", font=("Arial", 9), bg=bg_color, fg="gray").pack(anchor=tk.W)
            
            # Логика стоимости с зачеркиванием старой цены при наличии скидки (Практика 4 и 5)
            price_frame = tk.Frame(info_frame, bg=bg_color)
            price_frame.pack(anchor=tk.W, pady=5)
            tk.Label(price_frame, text="Цена: ", font=("Arial", 10), bg=bg_color).pack(side=tk.LEFT)

            if discount > 0:
                try:
                    old_price = float(p.price)
                    new_price = old_price * (1 - discount / 100)
                    # Старая зачеркнутая цена (fg="red", overstrike)
                    tk.Label(price_frame, text=f"{old_price} руб.", fg="red", font=("Arial", 10, "overstrike"), bg=bg_color).pack(side=tk.LEFT, padx=(0, 7))
                    # Новая цена крупным шрифтом
                    tk.Label(price_frame, text=f"{new_price:.2f} руб.", fg="black", font=("Arial", 10, "bold"), bg=bg_color).pack(side=tk.LEFT)
                except Exception:
                    tk.Label(price_frame, text=f"{p.price} руб.", font=("Arial", 10, "bold"), bg=bg_color).pack(side=tk.LEFT)
            else:
                tk.Label(price_frame, text=f"{p.price} руб.", font=("Arial", 10, "bold"), bg=bg_color).pack(side=tk.LEFT)

            # Количество на складе
            tk.Label(info_frame, text=f"Наличие на складе: {int(qty)} {p.unit}", font=("Arial", 9, "italic"), bg=bg_color).pack(anchor=tk.W)

            # ----------------------------------------------------
            # БЛОК 3 (ПРАВЫЙ): Размер скидки товара
            # ----------------------------------------------------
            discount_frame = tk.Frame(card_frame, bg=bg_color)
            discount_frame.pack(side=tk.RIGHT, padx=25, pady=10)

            tk.Label(discount_frame, text="Скидка", font=("Arial", 9), bg=bg_color, fg="gray").pack()
            # Если скидка большая (>10%), выделяем её жирным темно-зеленым цветом
            discount_color = "darkgreen" if discount > 10 else "black"
            tk.Label(discount_frame, text=f"{p.discount}%", font=("Arial", 16, "bold"), fg=discount_color, bg=bg_color).pack(pady=2)