first commit
This commit is contained in:
BIN
__pycache__/custom_file_dialog.cpython-312.pyc
Normal file
BIN
__pycache__/custom_file_dialog.cpython-312.pyc
Normal file
Binary file not shown.
257
custom_file_dialog.py
Normal file
257
custom_file_dialog.py
Normal file
@@ -0,0 +1,257 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
import os
|
||||
from functools import partial
|
||||
|
||||
|
||||
class CustomFileDialog(tk.Toplevel):
|
||||
def __init__(self, parent, initial_dir=None, filetypes=None):
|
||||
super().__init__(parent)
|
||||
self.parent = parent
|
||||
self.title("Datei auswählen")
|
||||
self.geometry("800x600") # Standardgröße, kann angepasst werden
|
||||
# Macht das Dialogfenster modal zum Hauptfenster
|
||||
self.transient(parent)
|
||||
self.grab_set() # Fängt alle Ereignisse ab, bis der Dialog geschlossen wird
|
||||
|
||||
self.selected_file = None
|
||||
self.current_dir = os.path.abspath(
|
||||
initial_dir) if initial_dir else os.getcwd()
|
||||
self.filetypes = filetypes if filetypes else [("All files", "*.*")]
|
||||
self.current_filter_pattern = "*.*" # Standardfilter
|
||||
|
||||
# Icons (Platzhalter, müssten geladen werden)
|
||||
# Sie müssen hier Ihre eigenen Icons laden oder generieren
|
||||
# Beispiel: self.folder_icon = tk.PhotoImage(file="path/to/your/folder_icon.png")
|
||||
# Für den Anfang verwenden wir leere PhotoImages
|
||||
self.folder_icon = tk.PhotoImage(
|
||||
file="./water-folder.png")
|
||||
self.file_icon = tk.PhotoImage(
|
||||
file="./text-x-generic.png")
|
||||
self.iso_icon = tk.PhotoImage(
|
||||
file="./media-optical.png")
|
||||
|
||||
self._create_widgets()
|
||||
|
||||
# Filter-Combobox initialisieren
|
||||
filter_descriptions = [desc for desc, pattern in self.filetypes]
|
||||
self.filter_combobox["values"] = filter_descriptions
|
||||
# Ersten Filter als Standard setzen
|
||||
self.filter_combobox.set(filter_descriptions[0])
|
||||
# Den initialen Filter explizit setzen, da <<ComboboxSelected>> nicht immer ausgelöst wird
|
||||
self.current_filter_pattern = self.filetypes[0][1]
|
||||
|
||||
self._populate_files()
|
||||
|
||||
# Behandelt das Schließen des Fensters
|
||||
self.protocol("WM_DELETE_WINDOW", self._on_closing)
|
||||
self.wait_window(self) # Wartet, bis das Fenster geschlossen wird
|
||||
|
||||
def _create_widgets(self):
|
||||
# Hauptframe
|
||||
main_frame = ttk.Frame(self, padding="10")
|
||||
main_frame.pack(fill="both", expand=True)
|
||||
# Canvas-Bereich soll sich ausdehnen
|
||||
main_frame.grid_rowconfigure(1, weight=1)
|
||||
main_frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
# Pfad-Navigation
|
||||
path_frame = ttk.Frame(main_frame)
|
||||
path_frame.grid(row=0, column=0, sticky="ew", pady=(0, 5))
|
||||
path_frame.grid_columnconfigure(1, weight=1)
|
||||
|
||||
ttk.Button(path_frame, text="Up", command=self._go_up_dir).grid(
|
||||
row=0, column=0, padx=(0, 5))
|
||||
self.path_entry = ttk.Entry(path_frame, state="readonly")
|
||||
self.path_entry.grid(row=0, column=1, sticky="ew")
|
||||
|
||||
ttk.Label(path_frame, text="Dateityp:").grid(
|
||||
row=0, column=2, padx=(10, 5))
|
||||
self.filter_combobox = ttk.Combobox(path_frame, state="readonly")
|
||||
self.filter_combobox.grid(row=0, column=3, sticky="ew")
|
||||
self.filter_combobox.bind(
|
||||
"<<ComboboxSelected>>", self._on_filter_select)
|
||||
# Optional: Pfad im System-Explorer öffnen
|
||||
# Canvas für Dateianzeige (Kachelansicht)
|
||||
self.canvas_frame = ttk.Frame(main_frame)
|
||||
self.canvas_frame.grid(row=1, column=0, sticky="nsew")
|
||||
self.canvas_frame.grid_rowconfigure(0, weight=1)
|
||||
self.canvas_frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
self.canvas = tk.Canvas(
|
||||
self.canvas_frame, bg="white", highlightthickness=0)
|
||||
self.canvas.grid(row=0, column=0, sticky="nsew")
|
||||
|
||||
self.v_scrollbar = ttk.Scrollbar(
|
||||
self.canvas_frame, orient="vertical", command=self.canvas.yview)
|
||||
self.v_scrollbar.grid(row=0, column=1, sticky="ns")
|
||||
self.canvas.configure(yscrollcommand=self.v_scrollbar.set)
|
||||
|
||||
self.h_scrollbar = ttk.Scrollbar(
|
||||
self.canvas_frame, orient="horizontal", command=self.canvas.xview)
|
||||
self.h_scrollbar.grid(row=1, column=0, sticky="ew")
|
||||
self.canvas.configure(xscrollcommand=self.h_scrollbar.set)
|
||||
|
||||
# Frame zum Halten der Kacheln
|
||||
self.inner_frame = ttk.Frame(self.canvas)
|
||||
self.canvas.create_window((0, 0), window=self.inner_frame, anchor="nw")
|
||||
|
||||
self.inner_frame.bind("<Configure>", lambda e: self.canvas.configure(
|
||||
scrollregion=self.canvas.bbox("all")))
|
||||
# Für Klicks auf leeren Bereich
|
||||
self.canvas.bind("<Button-1>", self._on_canvas_click)
|
||||
|
||||
# Buttons
|
||||
button_frame = ttk.Frame(main_frame)
|
||||
button_frame.grid(row=2, column=0, sticky="ew", pady=(5, 0))
|
||||
button_frame.grid_columnconfigure(0, weight=1) # Leerraum links
|
||||
ttk.Button(button_frame, text="Öffnen", command=self._on_open).grid(
|
||||
row=0, column=1, padx=(0, 5))
|
||||
ttk.Button(button_frame, text="Abbrechen",
|
||||
command=self._on_cancel).grid(row=0, column=2)
|
||||
|
||||
def _populate_files(self):
|
||||
# Lösche alle vorhandenen Kacheln
|
||||
for widget in self.inner_frame.winfo_children():
|
||||
widget.destroy()
|
||||
|
||||
self.path_entry.config(state="normal")
|
||||
self.path_entry.delete(0, tk.END)
|
||||
self.path_entry.insert(0, self.current_dir)
|
||||
self.path_entry.config(state="readonly")
|
||||
|
||||
files_and_dirs = []
|
||||
try:
|
||||
for item in os.listdir(self.current_dir):
|
||||
full_path = os.path.join(self.current_dir, item)
|
||||
if os.path.isdir(full_path):
|
||||
files_and_dirs.append((item, "dir"))
|
||||
elif os.path.isfile(full_path):
|
||||
# Dateien nur hinzufügen, wenn sie dem aktuellen Filter entsprechen
|
||||
if self._matches_filetype(item):
|
||||
files_and_dirs.append((item, "file"))
|
||||
except PermissionError:
|
||||
# Fehlerbehandlung für nicht zugängliche Verzeichnisse
|
||||
ttk.Label(self.inner_frame,
|
||||
text="Zugriff verweigert.").pack(pady=20)
|
||||
return
|
||||
except Exception as e:
|
||||
ttk.Label(self.inner_frame, text=f"Fehler: {e}").pack(pady=20)
|
||||
return
|
||||
|
||||
# Sortieren: Ordner zuerst, dann Dateien, alphabetisch
|
||||
files_and_dirs.sort(key=lambda x: (x[1] == "file", x[0].lower()))
|
||||
|
||||
# Kachel-Layout (Beispiel: 4 Spalten)
|
||||
col_count = 4
|
||||
for i, (name, item_type) in enumerate(files_and_dirs):
|
||||
row = i // col_count
|
||||
col = i % col_count
|
||||
|
||||
icon = self.folder_icon if item_type == "dir" else (
|
||||
self.iso_icon if name.lower().endswith(".iso") else self.file_icon)
|
||||
|
||||
# Kachel-Frame
|
||||
item_frame = ttk.Frame(
|
||||
self.inner_frame, relief="solid", borderwidth=1, padding=5)
|
||||
item_frame.grid(row=row, column=col, padx=5, pady=5, sticky="nsew")
|
||||
# Text soll sich ausdehnen
|
||||
item_frame.grid_rowconfigure(1, weight=1)
|
||||
item_frame.grid_columnconfigure(
|
||||
0, weight=1) # Icon/Text zentrieren
|
||||
|
||||
# Daten an den Frame anhängen
|
||||
item_frame.file_path = full_path
|
||||
item_frame.item_type = item_type
|
||||
|
||||
# Icon
|
||||
icon_label = ttk.Label(item_frame, image=icon)
|
||||
icon_label.grid(row=0, column=0, pady=(0, 5))
|
||||
# Daten an das Icon-Label anhängen
|
||||
icon_label.file_path = full_path
|
||||
icon_label.item_type = item_type
|
||||
|
||||
# Dateiname
|
||||
# wraplength für Zeilenumbruch
|
||||
name_label = ttk.Label(item_frame, text=name,
|
||||
wraplength=100, anchor="n")
|
||||
name_label.grid(row=1, column=0, sticky="ew")
|
||||
# Daten an das Name-Label anhängen
|
||||
name_label.file_path = full_path
|
||||
name_label.item_type = item_type
|
||||
|
||||
# Bindungen für Klicks (mit functools.partial)
|
||||
item_frame.bind(
|
||||
"<Button-1>", partial(self._on_item_click, full_path, item_type))
|
||||
icon_label.bind(
|
||||
"<Button-1>", partial(self._on_item_click, full_path, item_type))
|
||||
name_label.bind(
|
||||
"<Button-1>", partial(self._on_item_click, full_path, item_type))
|
||||
|
||||
item_frame.bind(
|
||||
"<Double-Button-1>", partial(self._on_item_double_click, full_path, item_type))
|
||||
icon_label.bind(
|
||||
"<Double-Button-1>", partial(self._on_item_double_click, full_path, item_type))
|
||||
name_label.bind(
|
||||
"<Double-Button-1>", partial(self._on_item_double_click, full_path, item_type))
|
||||
|
||||
def _go_up_dir(self):
|
||||
parent_dir = os.path.dirname(self.current_dir)
|
||||
if parent_dir != self.current_dir: # Verhindert, dass man über das Root-Verzeichnis hinausgeht
|
||||
self.current_dir = parent_dir
|
||||
self._populate_files()
|
||||
|
||||
def _on_item_click(self, path, item_type, event):
|
||||
print(f"DEBUG: _on_item_click - Path: {path}, Type: {item_type}")
|
||||
# Hier können Sie eine visuelle Auswahl hervorheben
|
||||
self.selected_file = path # Temporär speichern
|
||||
|
||||
def _on_item_double_click(self, path, item_type, event):
|
||||
print(
|
||||
f"DEBUG: _on_item_double_click - Path: {path}, Type: {item_type}")
|
||||
if item_type == "dir":
|
||||
self.current_dir = path
|
||||
self._populate_files()
|
||||
else:
|
||||
self.selected_file = path
|
||||
self.destroy() # Dialog schließen und ausgewählte Datei zurückgeben
|
||||
|
||||
def _on_open(self):
|
||||
if self.selected_file and os.path.isfile(self.selected_file):
|
||||
self.destroy()
|
||||
else:
|
||||
# Optional: Fehlermeldung, wenn keine Datei ausgewählt oder Ordner doppelt geklickt wurde
|
||||
print("Bitte eine Datei auswählen oder einen Ordner doppelt klicken.")
|
||||
|
||||
def _on_cancel(self):
|
||||
self.selected_file = None # Nichts ausgewählt
|
||||
self.destroy()
|
||||
|
||||
def _on_closing(self):
|
||||
self.selected_file = None # Nichts ausgewählt, wenn Fenster geschlossen wird
|
||||
self.destroy()
|
||||
|
||||
def _matches_filetype(self, filename):
|
||||
# Wenn der aktuelle Filter "*.*" ist, passen alle Dateien
|
||||
if self.current_filter_pattern == "*.*":
|
||||
return True
|
||||
|
||||
# Ansonsten prüfen, ob die Datei zum aktuellen spezifischen Filter passt
|
||||
ext = self.current_filter_pattern[2:].lower()
|
||||
return filename.lower().endswith("." + ext)
|
||||
|
||||
def _on_filter_select(self, event):
|
||||
selected_desc = self.filter_combobox.get()
|
||||
for desc, pattern in self.filetypes:
|
||||
if desc == selected_desc:
|
||||
self.current_filter_pattern = pattern
|
||||
break
|
||||
self._populate_files() # Dateiliste neu laden mit neuem Filter
|
||||
|
||||
def _on_canvas_click(self, event):
|
||||
# Wenn auf den leeren Bereich des Canvas geklickt wird, Auswahl aufheben
|
||||
self.selected_file = None
|
||||
# Optional: Visuelle Hervorhebung entfernen
|
||||
|
||||
def get_selected_file(self):
|
||||
return self.selected_file
|
39
mainwindow.py
Normal file
39
mainwindow.py
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/python3
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from custom_file_dialog import CustomFileDialog
|
||||
|
||||
|
||||
class GlotzMol(tk.Tk):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.geometry('800x400')
|
||||
ttk.Label(text="Custodialog-teschdfeschda").grid(row=0, column=0)
|
||||
self.columnconfigure(1, weight=1)
|
||||
self.iso_path_entry = ttk.Entry(self)
|
||||
self.iso_path_entry.grid(
|
||||
row=1, column=0, columnspan=2, padx=15, pady=5, sticky="ew")
|
||||
ttk.Button(self, text="Öffnen", command=self.customtest).grid(
|
||||
row=2, column=0, padx=5, pady=5)
|
||||
|
||||
def customtest(self):
|
||||
dialog = CustomFileDialog(self, initial_dir="/home/punix/Downloads",
|
||||
filetypes=[("ISO files", "*.iso")])
|
||||
path = dialog.get_selected_file()
|
||||
|
||||
if path:
|
||||
self.iso_path_entry.delete(0, tk.END)
|
||||
self.iso_path_entry.insert(0, path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
root = GlotzMol()
|
||||
theme_path = '/usr/share/TK-Themes'
|
||||
style = ttk.Style(root)
|
||||
root.tk.call('source', f"{theme_path}/water.tcl")
|
||||
try:
|
||||
root.tk.call('set_theme', 'dark')
|
||||
except tk.TclError:
|
||||
pass
|
||||
root.mainloop()
|
BIN
media-optical.png
Normal file
BIN
media-optical.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
text-x-generic.png
Normal file
BIN
text-x-generic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 612 B |
BIN
water-folder.png
Normal file
BIN
water-folder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
Reference in New Issue
Block a user