Próbuję utworzyć aplikację z kategorii pakowanie paczek. Nie dam rady z algorytmami umieszczania paczek ale przydałby mi się programik który wizualnie pokarze rozmieszczenie. Zacząłem pisać kod ale nie bardzo wiem jak przenosić paczki pomiędzy oknami? Jak aktualizować kontenery i paczki w swoich oknach aby metoda drag and drop działała. Trzeba na bieżąco aktualizować na której kanwie dana paczka/kontener jest.

Poniższy program pokarze mniej więcej jak powinien wyglądać efekt końcowy. Aby "zadziałał" trzeba wcisnąć przyciski "Paczki" i "Kontenery" oraz wskazać plik txt z zawartością np. "24x34
34x35"

Kopiuj
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
import re
import logging

paczki = []
kontenery = []


# Funkcja do obsługi przycisku "Paczki" i "Kontenery"
def open_file(source):
    # Otwórz okno wyboru pliku
    file_path = filedialog.askopenfilename(
        title="Wybierz plik",
        filetypes=[("Pliki tekstowe", "*.txt")]
    )

    # Jeśli użytkownik wybrał plik, odczytaj jego zawartość i wypisz ją w konsoli
    if file_path:
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                licznik = 1
                for line in file:
                    # Dopasowanie dwóch pierwszych liczb (całych liczb całkowitych)
                    liczby = re.findall(r'-?\d+', line)
                    if len(liczby) >= 2:
                        # Dodajemy dwie pierwsze liczby do paczki jako krotkę
                        if source == "Paczki":
                            paczki.append((licznik, int(liczby[0]), int(liczby[1])))
                            licznik += 1
                        else:
                            kontenery.append((licznik, int(liczby[0]), int(liczby[1])))
                            licznik += 1
            if len(paczki) > 0 and len(kontenery) > 0:
                logging.debug(f'{paczki=},{kontenery=}')
                update_canvas()
        except Exception as e:
            print(f"Nie udało się odczytać pliku: {e}")


# Funkcja do aktualizacji kanw w lewym panelu
def update_canvas():

    canvas = lg_canvas
    items = paczki
    color = "lightblue"


    canvas.delete("all")  # Wyczyść obecne rysunki

    # Rysowanie prostokątów
    y_offset = 10  # Odstęp między prostokątami
    width_reprezentacji = 120
    height_reprezentacji = 30
    for item in items:
        # Item[1] to szerokość, item[2] to wysokość
        width = item[1]
        height = item[2]
        # Rysowanie prostokąta
        canvas.create_rectangle(10, y_offset, 10 + width_reprezentacji, y_offset + height_reprezentacji, fill=color)
        canvas.create_text(10 + width_reprezentacji / 2, y_offset + height_reprezentacji / 2, text=f"{width}x{height}", fill="black")

        y_offset += height_reprezentacji + 10  # Przesunięcie w dół na następny prostokąt

    canvas = ld_canvas
    items = kontenery
    color = "lightgreen"


    canvas.delete("all")  # Wyczyść obecne rysunki

    # Rysowanie prostokątów
    y_offset = 10
    for item in items:
        # Item[1] to szerokość, item[2] to wysokość
        width = item[1]
        height = item[2]
        # Rysowanie prostokąta
        canvas.create_rectangle(10, y_offset, 10 + width_reprezentacji, y_offset + height_reprezentacji, fill=color)
        canvas.create_text(10 + width_reprezentacji / 2, y_offset + height_reprezentacji / 2, text=f"{width}x{height}", fill="black")

        y_offset += height_reprezentacji + 10  # Przesunięcie w dół na następny prostokąt


# Główna aplikacja
def main():
    logging.basicConfig(level=logging.DEBUG,  # filename="paczki_log.log",
                        format='%(asctime)s - %(levelname)s - %(message)s')
    logging.debug("-------------Rozpoczęcie programu------------------")  # debug,info,warning,critical
    global lg_canvas, ld_canvas  # Umożliwiamy dostęp do kanw z funkcji update_canvas
    root = tk.Tk()
    root.title("Paczki v0.1")
    root.minsize(900, 500)

    # Lewe górne okno
    lg_frame = ttk.Frame(root)
    lg_frame.place(x=0, y=0, relwidth=0.2, relheight=0.6)

    # Przycisk na górze lewego okna
    button_paczki = ttk.Button(lg_frame, text="Paczki", command=lambda: open_file("Paczki"))
    button_paczki.place(x=10, y=10, relwidth=0.8)  # Ustawienie przycisku na górze (10px od góry i 10px od lewej)

    lg_canvas = tk.Canvas(lg_frame, width=120, height=300)
    lg_scrollbar = ttk.Scrollbar(lg_frame, orient="vertical", command=lg_canvas.yview)
    lg_canvas.configure(yscrollcommand=lg_scrollbar.set)
    lg_canvas.place(x=0, y=40, relwidth=0.9, relheight=1)  # Przesunięcie o 40px w dół, by nie nakładał się na przycisk
    lg_scrollbar.place(relx=0.9, y=0, relwidth=0.1, relheight=1)

    lg_canvas.config(scrollregion=lg_canvas.bbox("all"))

    # Lewe dolne okno
    ld_frame = ttk.Frame(root)
    ld_frame.place(x=0, rely=0.6, relwidth=0.2, relheight=0.4)

    # Przycisk na górze lewego okna
    button_kontenery = ttk.Button(ld_frame, text="Kontenery", command=lambda: open_file("Kontenery"))
    button_kontenery.place(x=10, y=10, relwidth=0.8)  # Ustawienie przycisku na górze (10px od góry i 10px od lewej)

    ld_canvas = tk.Canvas(ld_frame, width=120, height=300)
    ld_scrollbar = ttk.Scrollbar(ld_frame, orient="vertical", command=ld_canvas.yview)
    ld_canvas.configure(yscrollcommand=ld_scrollbar.set)
    ld_canvas.place(x=0, y=40, relwidth=0.9, relheight=1)
    ld_scrollbar.place(relx=0.9, y=0, relwidth=0.1, relheight=1)

    ld_canvas.config(scrollregion=ld_canvas.bbox("all"))

    # Prawe okno
    right_frame = ttk.Frame(root)
    right_frame.place(relx=0.2, y=0, relwidth=0.8, relheight=1)
    right_canvas = tk.Canvas(right_frame, width=120, height=300)
    right_scrollbar = ttk.Scrollbar(right_frame, orient="horizontal", command=right_canvas.xview)
    right_canvas.configure(xscrollcommand=right_scrollbar.set)
    right_canvas.place(x=0, y=0, relwidth=1, relheight=1)
    right_scrollbar.place(x=0, rely=0.9, relwidth=1, relheight=0.1)

    right_canvas.create_rectangle(20,20,100,200,fill = 'lightgreen')
    right_canvas.create_rectangle(40, 40, 60, 70, fill='lightblue')

    right_canvas.create_rectangle(220,20,400,400,fill = 'lightgreen')
    right_canvas.create_rectangle(240, 240, 310, 310, fill='lightblue')

    right_canvas.config(scrollregion=right_canvas.bbox("all"))

    # Uruchomienie pętli głównej
    root.mainloop()


# Sprawdzenie, czy plik jest uruchamiany bezpośrednio
if __name__ == "__main__":
    main()

Może lepiej na jednej kanwie tylko podzielić liniami? Tylko wtedy jak zrobić przewijanie jeżeli będzie więcej paczek. Jak proponujecie podejść do tematu aby takiemu laikowi jak ja udało się to stworzyć?