Untitled

 avatar
unknown
plain_text
a month ago
6.2 kB
2
Indexable
import tkinter as tk
from tkinter import filedialog, messagebox
from tkinter import ttk
from openpyxl import load_workbook
import os
import json

CONFIG_FILE = "config.json"

class ExcelViewer(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Excel Viewer")
        self.geometry("1000x563")

        # Treeview erstellen
        self.treeview = ttk.Treeview(self, selectmode="browse", show="headings")
        self.treeview.pack(fill="both", expand=True)

        self.columns = []
        self.file_path = None

        # Sortierstatus initialisieren
        self.sort_reverse = {}  # Speichert den Sortierstatus für jede Spalte

        self.load_config()
        self.create_menu()

        # Binde das Ereignis für Größenänderung
        self.bind("<Configure>", self.adjust_column_widths)

    def create_menu(self):
        menu = tk.Menu(self)
        self.config(menu=menu)
        menu.add_command(label="Datei auswählen", command=self.select_file)

    def save_config(self):
        config = {
            "file_path": self.file_path,
            "columns": self.columns
        }
        with open(CONFIG_FILE, "w") as f:
            json.dump(config, f, indent=4)

    def load_config(self):
        if os.path.exists(CONFIG_FILE):
            with open(CONFIG_FILE, "r") as f:
                config = json.load(f)
                self.file_path = config.get("file_path")
                self.columns = config.get("columns", [])
                if self.file_path and self.columns:
                    self.load_excel_data(self.file_path)

    def select_file(self):
        self.file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
        if self.file_path:
            self.save_config()
            self.load_excel_data(self.file_path)

    def load_excel_data(self, file_path):
        try:
            workbook = load_workbook(file_path)
            sheet = workbook.active

            # Treeview zurücksetzen
            self.treeview.delete(*self.treeview.get_children())
            self.treeview["columns"] = []

            # Header aus der Excel-Datei holen
            headers = [cell.value for cell in next(sheet.iter_rows())]

            # Konfiguration prüfen
            if not self.columns:
                # Feste Spaltenbreite setzen
                self.columns = [
                    {"header": header, "alignment": "center", "width": 150}  # Feste Breite von 150
                    for header in headers
                ]
                self.save_config()

            # Treeview konfigurieren
            self.treeview["columns"] = [col["header"] for col in self.columns]

            for column in self.columns:
                header_name = column["header"]
                self.treeview.heading(
                    header_name,
                    text=header_name,
                    command=lambda c=header_name: self.sort_column(c)
                )
                self.treeview.column(header_name,
                                     width=column["width"],
                                     anchor=self.get_anchor(column["alignment"]))

                # Initialisierungsstatus der Sortierfolge
                if header_name not in self.sort_reverse:
                    self.sort_reverse[header_name] = False

            # Daten einfügen, nur wenn mindestens eine Zelle der Zeile nicht leer ist
            for row in sheet.iter_rows(min_row=2, values_only=True):
                if any(value is not None and value != "" for value in
                       row):  # Prüft, ob mindestens eine Zelle nicht leer ist
                    row_values = [
                        value if value is not None else ""  # None-Werte durch leeren String ersetzen
                        for value in row
                    ]
                    self.treeview.insert("", "end", values=row_values)

        except Exception as e:
            messagebox.showerror("Fehler", f"Konnte Datei nicht laden: {e}")

    def sort_column(self, column):
        """Sortiert die Treeview-Einträge nach der angegebenen Spalte und zeigt ein Symbol für die Sortierreihenfolge."""
        data = [
            (self.treeview.item(item, "values"), item)
            for item in self.treeview.get_children("")
        ]

        # Spaltenindex anhand des Spaltennamens
        col_idx = self.treeview["columns"].index(column)

        # Sortieren: Alle Werte als Strings behandeln
        sorted_data = sorted(
            data,
            key=lambda x: str(x[0][col_idx]),
            reverse=self.sort_reverse[column]
        )

        # Sortierfolge umkehren
        self.sort_reverse[column] = not self.sort_reverse[column]

        # Treeview zurücksetzen und neu sortierte Einträge einfügen
        for index, (_, item_id) in enumerate(sorted_data):
            self.treeview.move(item_id, "", index)

        # Überschriften aktualisieren
        self.update_headers(column)

    def update_headers(self, sorted_column):
        """Aktualisiert die Spaltenüberschriften und fügt ein Sortiersymbol hinzu."""
        for column in self.treeview["columns"]:
            # Entferne vorhandene Symbole
            base_text = column
            if column.endswith(" ▲") or column.endswith(" ▼"):
                base_text = column[:-2]

            # Füge ein Symbol für die sortierte Spalte hinzu
            if column == sorted_column:
                sort_symbol = "▲" if not self.sort_reverse[column] else "▼"
                self.treeview.heading(column, text=f"{base_text} {sort_symbol}")
            else:
                self.treeview.heading(column, text=base_text)

    def adjust_column_widths(self, event=None):
        """Passt die Spaltenbreiten an, aber nur für die Spalten mit festen Breiten."""
        # Keine Veränderung der Spaltenbreiten hier, da die Spalten feste Breiten haben

    def get_anchor(self, alignment):
        if alignment == "left":
            return "w"
        elif alignment == "center":
            return "center"
        elif alignment == "right":
            return "e"
        return "w"

if __name__ == "__main__":
    app = ExcelViewer()
    app.mainloop()
Leave a Comment