Untitled
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