commit 43

This commit is contained in:
2025-08-03 00:56:28 +02:00
parent 369605be8a
commit b1394e0f62
7 changed files with 138 additions and 52 deletions

View File

@@ -60,7 +60,7 @@ class AppConfig:
# UI configuration
UI_CONFIG: Dict[str, Any] = {
"window_title": "File Dialog",
"window_size": (1100, 850),
"window_size": (1050, 850),
"font_family": "Ubuntu",
"font_size": 11,
"resizable_window": (True, True),

View File

@@ -369,32 +369,50 @@ class WidgetManager:
left_bottom_buttons, text="", anchor="w", style="AccentBottom.TLabel")
if self.dialog.dialog_mode == "save":
self.filename_entry = ttk.Entry(left_bottom_buttons, width=50)
self.filename_entry.grid(
row=0, column=1, padx=(5, 5), pady=5, sticky="ew")
left_bottom_buttons.grid_columnconfigure(1, weight=1)
ttk.Button(left_bottom_buttons, text="Speichern",
command=self.dialog.on_save).grid(row=0, column=0, padx=(10, 5), pady=10)
ttk.Button(left_bottom_buttons, text="Abbrechen",
command=self.dialog.on_cancel).grid(row=1, column=0, padx=(10, 5))
self.status_bar.grid(row=2, column=0, columnspan=2,
sticky="ew", padx=10, pady=5)
# Widgets for save mode
self.filename_entry = ttk.Entry(left_bottom_buttons, width=60)
self.filename_entry.grid(row=0, column=1, padx=(
0, 5), pady=(10, 10), sticky="ew")
save_button = ttk.Button(
left_bottom_buttons, text="Speichern", command=self.dialog.on_save)
save_button.grid(row=0, column=0, padx=(10, 5), pady=10)
cancel_button = ttk.Button(
left_bottom_buttons, text="Abbrechen", command=self.dialog.on_cancel)
cancel_button.grid(row=1, column=0, padx=(10, 5), pady=(0, 10))
self.filter_combobox = ttk.Combobox(left_bottom_buttons, values=[
ft[0] for ft in self.dialog.filetypes], state="readonly")
self.filter_combobox.grid(
row=1, column=1, sticky="w", padx=(0, 10), pady=(0, 10))
self.filter_combobox.bind(
"<<ComboboxSelected>>", self.dialog.on_filter_change)
self.filter_combobox.set(self.dialog.filetypes[0][0])
self.status_bar.grid(
row=0, column=1, sticky="w", padx=0, pady=(0, 5))
else:
# Open mode layout
left_bottom_buttons.grid_columnconfigure(1, weight=1)
# Status bar (top-left in the bottom area)
self.status_bar.grid(row=0, column=1, columnspan=2,
sticky="e", padx=10, pady=5)
ttk.Button(left_bottom_buttons, text="Öffnen", command=self.dialog.on_open).grid(
row=0, column=0, padx=(10, 5), pady=10)
ttk.Button(left_bottom_buttons, text="Abbrechen",
command=self.dialog.on_cancel).grid(row=1, column=0, padx=(10, 5))
open_button = ttk.Button(
left_bottom_buttons, text="Öffnen", command=self.dialog.on_open)
open_button.grid(row=0, column=0, padx=(10, 5), pady=10)
# Filter combobox (bottom-right)
self.filter_combobox = ttk.Combobox(left_bottom_buttons, values=[
ft[0] for ft in self.dialog.filetypes], state="readonly")
self.filter_combobox.grid(
row=1, column=1, sticky="w", padx=(5, 10))
self.filter_combobox.bind(
"<<ComboboxSelected>>", self.dialog.on_filter_change)
self.filter_combobox.set(self.dialog.filetypes[0][0])
cancel_button = ttk.Button(
left_bottom_buttons, text="Abbrechen", command=self.dialog.on_cancel)
cancel_button.grid(row=1, column=0, padx=(10, 5), pady=(0, 10))
self.filter_combobox = ttk.Combobox(left_bottom_buttons, values=[
ft[0] for ft in self.dialog.filetypes], state="readonly")
self.filter_combobox.grid(
row=1, column=1, sticky="w", padx=(0, 10), pady=(0, 10))
self.filter_combobox.bind(
"<<ComboboxSelected>>", self.dialog.on_filter_change)
self.filter_combobox.set(self.dialog.filetypes[0][0])
self.status_bar.grid(row=0, column=1, sticky="w", padx=0, pady=5)

View File

@@ -151,6 +151,7 @@ class CustomFileDialog(tk.Toplevel):
self.original_path_text = self.widget_manager.path_entry.get()
self.widget_manager.path_entry.delete(0, tk.END)
self.widget_manager.path_entry.insert(0, "Suchbegriff eingeben...")
self.widget_manager.path_entry.focus_set() # Set focus to path entry
self.widget_manager.path_entry.bind(
"<Return>", self.execute_search)
self.widget_manager.path_entry.bind(
@@ -371,6 +372,30 @@ class CustomFileDialog(tk.Toplevel):
except (FileNotFoundError, PermissionError):
continue
# Bind selection event
def on_search_select(event):
selection = search_tree.selection()
if selection:
item = search_tree.item(selection[0])
filename = item['text'].strip()
directory = item['values'][0]
full_path = os.path.join(directory, filename)
# Update status bar
try:
stat = os.stat(full_path)
size_str = self._format_size(stat.st_size)
self.widget_manager.status_bar.config(text=f"'{filename}' Größe: {size_str}")
except (FileNotFoundError, PermissionError):
self.widget_manager.status_bar.config(text=f"'{filename}' nicht zugänglich")
# If in save mode, update filename entry
if self.dialog_mode == "save":
self.widget_manager.filename_entry.delete(0, tk.END)
self.widget_manager.filename_entry.insert(0, filename)
search_tree.bind("<<TreeviewSelect>>", on_search_select)
# Bind double-click to select file
def on_search_double_click(event):
selection = search_tree.selection()
@@ -392,7 +417,7 @@ class CustomFileDialog(tk.Toplevel):
self.unbind_all("<Button-4>")
self.unbind_all("<Button-5>")
def populate_files(self, item_to_rename=None):
def populate_files(self, item_to_rename=None, item_to_select=None):
# Unbind previous global mouse wheel events
self._unbind_mouse_wheel_events()
@@ -403,9 +428,9 @@ class CustomFileDialog(tk.Toplevel):
self.selected_file = None
self.update_status_bar()
if self.view_mode.get() == "list":
self.populate_list_view(item_to_rename)
self.populate_list_view(item_to_rename, item_to_select)
else:
self.populate_icon_view(item_to_rename)
self.populate_icon_view(item_to_rename, item_to_select)
def _get_sorted_items(self):
try:
@@ -425,7 +450,22 @@ class CustomFileDialog(tk.Toplevel):
except FileNotFoundError:
return ([], "Verzeichnis nicht gefunden.", None)
def populate_icon_view(self, item_to_rename=None):
def _get_folder_content_count(self, folder_path):
try:
if not os.path.isdir(folder_path) or not os.access(folder_path, os.R_OK):
return None
items = os.listdir(folder_path)
# Filter based on hidden files setting
if not self.show_hidden_files.get():
items = [item for item in items if not item.startswith('.')]
return len(items)
except (PermissionError, FileNotFoundError):
return None
def populate_icon_view(self, item_to_rename=None, item_to_select=None):
canvas = tk.Canvas(self.widget_manager.file_list_frame,
highlightthickness=0, bg=self.style_manager.icon_bg_color)
v_scrollbar = ttk.Scrollbar(
@@ -488,7 +528,14 @@ class CustomFileDialog(tk.Toplevel):
name_label = ttk.Label(item_frame, text=self.shorten_text(
name, 14), anchor="center", style="Item.TLabel")
name_label.pack(fill="x", expand=True)
Tooltip(item_frame, name)
tooltip_text = name
if is_dir:
content_count = self._get_folder_content_count(path)
if content_count is not None:
tooltip_text += f"\n({content_count} Einträge)"
Tooltip(item_frame, tooltip_text)
# Bind events to all individual widgets so scrolling works everywhere
for widget in [item_frame, icon_label, name_label]:
widget.bind("<Double-Button-1>", lambda e,
@@ -501,11 +548,15 @@ class CustomFileDialog(tk.Toplevel):
widget.bind("<F2>", lambda e, p=path,
f=item_frame: self.on_rename_request(e, p, f))
if name == item_to_select:
self.on_item_select(path, item_frame)
canvas.yview_moveto(row / max(1, (len(items) // col_count)))
col = (col + 1) % col_count
if col == 0:
row += 1
def populate_list_view(self, item_to_rename=None):
def populate_list_view(self, item_to_rename=None, item_to_select=None):
tree_frame = ttk.Frame(self.widget_manager.file_list_frame)
tree_frame.pack(fill='both', expand=True)
tree_frame.grid_rowconfigure(0, weight=1)
@@ -571,7 +622,12 @@ class CustomFileDialog(tk.Toplevel):
if name == item_to_rename:
self.tree.selection_set(item_id)
self.tree.focus(item_id)
self.tree.see(item_id) # Scroll to the item
self.start_rename(item_id, path)
elif name == item_to_select:
self.tree.selection_set(item_id)
self.tree.focus(item_id)
self.tree.see(item_id) # Scroll to the item
except (FileNotFoundError, PermissionError):
continue
@@ -589,9 +645,10 @@ class CustomFileDialog(tk.Toplevel):
self.selected_item_frame = item_frame
self.selected_file = path
self.update_status_bar()
self.bind("<F2>", lambda e, p=path, f=item_frame: self.on_rename_request(e, p, f))
if self.dialog_mode == "save" and not os.path.isdir(path):
self.widget_manager.path_entry.delete(0, tk.END)
self.widget_manager.path_entry.insert(0, path)
self.widget_manager.filename_entry.delete(0, tk.END)
self.widget_manager.filename_entry.insert(0, os.path.basename(path))
def on_list_select(self, event):
if not self.tree.selection():
@@ -601,8 +658,8 @@ class CustomFileDialog(tk.Toplevel):
self.selected_file = os.path.join(self.current_dir, item_text)
self.update_status_bar()
if self.dialog_mode == "save" and not os.path.isdir(self.selected_file):
self.widget_manager.path_entry.delete(0, tk.END)
self.widget_manager.path_entry.insert(0, self.selected_file)
self.widget_manager.filename_entry.delete(0, tk.END)
self.widget_manager.filename_entry.insert(0, item_text)
def on_rename_request(self, event, item_path=None, item_frame=None):
if self.view_mode.get() == "list":
@@ -686,6 +743,7 @@ class CustomFileDialog(tk.Toplevel):
self.populate_files()
self.update_nav_buttons()
self.update_status_bar()
self.update_action_buttons_state()
def go_forward(self):
if self.history_pos < len(self.history) - 1:
@@ -694,6 +752,7 @@ class CustomFileDialog(tk.Toplevel):
self.populate_files()
self.update_nav_buttons()
self.update_status_bar()
self.update_action_buttons_state()
def update_nav_buttons(self):
self.widget_manager.back_button.config(
@@ -784,7 +843,7 @@ class CustomFileDialog(tk.Toplevel):
entry = ttk.Entry(item_frame)
entry.insert(0, os.path.basename(item_path))
entry.select_range(0, tk.END)
entry.pack(fill="both", expand=True, padx=5, pady=5)
entry.pack(fill="x", expand=True, padx=5, pady=5)
entry.focus_set()
def finish_rename(event):
@@ -794,14 +853,17 @@ class CustomFileDialog(tk.Toplevel):
if os.path.exists(new_path):
self.widget_manager.status_bar.config(
text=f"'{new_name}' existiert bereits.")
self.populate_files()
self.populate_files(item_to_select=os.path.basename(item_path))
return
try:
os.rename(item_path, new_path)
self.populate_files(item_to_select=new_name)
except Exception as e:
self.widget_manager.status_bar.config(
text=f"Fehler beim Umbenennen: {e}")
self.populate_files()
self.populate_files()
else:
self.populate_files(item_to_select=os.path.basename(item_path))
def cancel_rename(event):
self.populate_files()
@@ -813,7 +875,9 @@ class CustomFileDialog(tk.Toplevel):
def _start_rename_list_view(self, item_id):
x, y, width, height = self.tree.bbox(item_id, column="#0")
entry = ttk.Entry(self.tree)
entry.place(x=x, y=y, width=width, height=height)
# Set a fixed width for the entry widget to prevent it from expanding too much
entry_width = self.tree.column("#0", "width")
entry.place(x=x, y=y, width=entry_width, height=height)
item_text = self.tree.item(item_id, "text").strip()
entry.insert(0, item_text)
@@ -829,14 +893,18 @@ class CustomFileDialog(tk.Toplevel):
if os.path.exists(new_path):
self.widget_manager.status_bar.config(
text=f"'{new_name}' existiert bereits.")
self.populate_files(item_to_select=item_text)
else:
try:
os.rename(old_path, new_path)
self.populate_files(item_to_select=new_name)
except Exception as e:
self.widget_manager.status_bar.config(
text=f"Fehler beim Umbenennen: {e}")
self.populate_files()
else:
self.populate_files(item_to_select=item_text)
entry.destroy()
self.populate_files()
def cancel_rename(event):
entry.destroy()

View File

@@ -30,23 +30,23 @@ class GlotzMol(tk.Tk):
def open_custom_dialog(self):
CustomFileDialog(self,
initial_dir=os.path.expanduser("~"),
filetypes=[("All Files", "*.*")
], dialog_mode="save")
dialog = CustomFileDialog(self,
initial_dir=os.path.expanduser("~"),
filetypes=[("All Files", "*.*")
])
# This is the crucial part: wait for the dialog to be closed
# self.wait_window(dialog)
self.wait_window(dialog)
# Now, get the result
# selected_path = dialog.get_selected_file()
selected_path = dialog.get_selected_file()
# if selected_path:
# self.iso_path_entry.delete(0, tk.END)
# self.iso_path_entry.insert(0, selected_path)
# print(f"Die ausgewählte Datei ist: {selected_path}")
# else:
# print("Keine Datei ausgewählt.")
if selected_path:
self.iso_path_entry.delete(0, tk.END)
self.iso_path_entry.insert(0, selected_path)
print(f"Die ausgewählte Datei ist: {selected_path}")
else:
print("Keine Datei ausgewählt.")
if __name__ == "__main__":