Files
dicom2pacs/gui.py

701 lines
29 KiB
Python
Executable File

import tkinter as tk
import shutil
from tkinter import filedialog, messagebox, font, ttk, simpledialog, Toplevel, Label, Entry, Button, Checkbutton, IntVar
import time
import os
from queue import Queue
import subprocess
def create_macos_button(parent, text, command=None, width=None, height=None, padx=10, pady=5):
"""Erstellt einen Button im macOS-Stil"""
# Verwende ttk.Button für besseres macOS-Aussehen
btn = ttk.Button(parent, text=text, command=command)
if width:
btn.config(width=width)
return btn
class SettingsDialog:
def __init__(self, parent, config):
self.config = config
self.top = Toplevel(parent)
self.top.title("Einstellungen")
# Erhöhe die Breite des Fensters
self.top.geometry('550x200') # Beispielgröße, anpassbar
Label(self.top, text="Server URL:").grid(row=0, column=0)
self.server_url_entry = Entry(self.top, width=40) # Erhöhe die Breite des Eingabefelds
self.server_url_entry.grid(row=0, column=1, padx=10, pady=5)
Label(self.top, text="Username:").grid(row=1, column=0)
self.username_entry = Entry(self.top, width=40) # Erhöhe die Breite des Eingabefelds
self.username_entry.grid(row=1, column=1, padx=10, pady=5)
Label(self.top, text="Password:").grid(row=2, column=0)
self.password_entry = Entry(self.top, show="*", width=40) # Erhöhe die Breite des Eingabefelds
self.password_entry.grid(row=2, column=1, padx=10, pady=5)
self.show_password_var = IntVar()
self.show_password_check = Checkbutton(self.top, text='Zeigen', variable=self.show_password_var, command=self.toggle_password_visibility)
self.show_password_check.grid(row=2, column=2)
# Checkbox für CD-Überprüfung hinzufügen
self.check_for_cd_var = IntVar(value=int(self.config.get('check_for_cd', '0')))
self.check_for_cd_check = Checkbutton(self.top, text="Bei Start nach CDs suchen", variable=self.check_for_cd_var)
self.check_for_cd_check.grid(row=3, column=0, columnspan=2, sticky="w", padx=10, pady=5)
self.load_config() # Laden der aktuellen Konfiguration
# Speichern-Button (macOS-Style)
save_btn = create_macos_button(self.top, text="Speichern", command=self.save_config)
save_btn.grid(row=4, column=1, pady=10)
def toggle_password_visibility(self):
"""Wechselt die Sichtbarkeit des Passworteingabefelds."""
if self.show_password_var.get() == 1:
self.password_entry.config(show="")
else:
self.password_entry.config(show="*")
def load_config(self):
config_path = os.path.join(os.path.expanduser('~'), '.dicom2pacs.conf')
try:
with open(config_path, 'r') as config_file:
for line in config_file:
key, value = line.strip().split('=', 1)
if key == 'server_url':
self.server_url_entry.insert(0, value)
elif key == 'server_username':
self.username_entry.insert(0, value)
elif key == 'server_pw':
self.password_entry.insert(0, value)
except FileNotFoundError:
print("Konfigurationsdatei nicht gefunden. Verwende Standardwerte.")
def save_config(self):
config = {
'server_url': self.server_url_entry.get(),
'server_username': self.username_entry.get(),
'server_pw': self.password_entry.get(),
'check_for_cd' : str(self.check_for_cd_var.get())
}
config_path = os.path.join(os.path.expanduser('~'), '.dicom2pacs.conf')
with open(config_path, 'w') as config_file:
for key, value in config.items():
config_file.write(f'{key}={value}\n')
self.top.destroy()
class GUI:
def __init__(self, on_folder_selected_callback, transfer_folder, on_close_callback, config):
self.config = config
self.on_folder_selected = on_folder_selected_callback
self.transfer_folder = transfer_folder
self.on_close = on_close_callback
self.root = tk.Tk()
self.root.title("Bilder einlesen")
# Erstellen der Menüleiste
menubar = tk.Menu(self.root)
self.root.config(menu=menubar) # Diese Zeile weist das 'menubar' Objekt dem 'menu' Attribut des Hauptfensters zu
# Erstellen des Einstellungsmenüs
settings_menu = tk.Menu(menubar, tearoff=0)
settings_menu.add_command(label="Einstellungen... \u2318,", command=self.open_settings_dialog)
menubar.add_cascade(label="Einstellungen", menu=settings_menu)
self.bind_shortcuts()
# Fenstergröße und -position festlegen
window_width = 350
window_height = 150
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
center_x = int(screen_width / 2 - window_width / 2)
center_y = int(screen_height / 2 - window_height / 2)
self.root.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
# Erstelle die Progressbar
self.progress = ttk.Progressbar(self.root, orient="horizontal", length=300, mode='determinate')
self.progress.pack(pady=20)
# Frame für die Buttons am unteren Rand des Fensters
self.button_frame = tk.Frame(self.root)
self.button_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=10)
# Durchsuchen Button (macOS-Style)
self.browse_button = create_macos_button(self.button_frame, text="Durchsuchen", command=self.browse)
self.browse_button.pack(side=tk.LEFT, padx=10, expand=True)
# Schließen Button (macOS-Style)
self.close_button = create_macos_button(self.button_frame, text="Abbruch", command=self.on_app_close)
self.close_button.pack(side=tk.RIGHT, padx=10, expand=True)
self.hint_label = tk.Label(self.root, text="Bitte wählen Sie den Ordner mit den Bilddaten aus!")
self.hint_label.pack(pady=5) # Pady hinzugefügt für etwas Abstand nach oben und unten
self.root.protocol("WM_DELETE_WINDOW", self.on_close)
self.searching = False
self.searching_label = None
self.labels_frame = tk.Frame(self.root) # Ein Frame für die animierten Labels
self.labels_frame.pack(fill=tk.BOTH, expand=True)
self.label_widgets = []
self.text_queue = Queue()
self.currently_animating = False
def save_cd_check_setting(self):
# Speichert den Zustand der Checkbox in der Konfigurationsdatei
self.config['check_for_cd'] = str(self.check_for_cd_var.get())
config_path = os.path.join(os.path.expanduser('~'), '.dicom2pacs.conf')
with open(config_path, 'w') as config_file:
for key, value in self.config.items():
config_file.write(f'{key}={value}\n')
def load_cd_check_setting(self):
# Lädt den Zustand der Checkbox aus der Konfigurationsdatei
self.check_for_cd_var.set(int(self.config.get('check_for_cd', 0)))
def start_animation(self, text):
self.text_queue.put(text)
if not self.currently_animating:
self.currently_animating = True
self.process_next_animation()
def process_next_animation(self):
if not self.text_queue.empty():
text = self.text_queue.get()
label = tk.Label(self.labels_frame, text=text)
label.pack()
self.label_widgets.append(label)
self.blink(label)
else:
self.currently_animating = False
def blink(self, label, is_visible=True):
if label in self.label_widgets and self.currently_animating:
label.config(foreground=self.root.cget('bg') if is_visible else 'black')
self.root.after(1000, lambda: self.blink(label, not is_visible))
def stop_animation(self):
self.currently_animating = False
self.clear_labels()
def clear_labels(self):
for label in self.label_widgets:
label.destroy()
self.label_widgets.clear()
def update_searching_label(self, text):
# Aktualisiere das Suchlabel
if hasattr(self, 'searching_label'):
self.searching_label.config(text=text)
self.root.update_idletasks()
def reset_progress(self, total_files):
self.progress['value'] = 0
self.progress['maximum'] = total_files
print("Fortschrittsanzeige wurde zurückgesetzt.")
self.root.update_idletasks()
def update_progress(self, incremental_progress, total_files):
if self.progress['value'] == 0 and incremental_progress == 0:
# Initialisierung bei Beginn des Upload-Prozesses
print("Initialisiere Fortschrittsanzeige auf 0")
else:
self.progress['value'] += incremental_progress
new_value = self.progress['value']
print(f"Aktualisiere Fortschritt: {new_value}/{total_files}")
print(f"Aktueller Wert der Progressbar: {new_value - incremental_progress}")
print(f"Neuer Wert der Progressbar: {new_value}")
self.progress['maximum'] = total_files
self.root.update_idletasks()
def start(self):
self.root.mainloop()
def browse(self):
# Öffne das Browse-Fenster
self.hint_label.pack_forget()
# Öffne standardmäßig den Downloads-Ordner
downloads_folder = os.path.join(os.path.expanduser('~'), 'Downloads')
if not os.path.exists(downloads_folder):
downloads_folder = os.path.expanduser('~') # Fallback auf Home-Verzeichnis
source_folder = filedialog.askdirectory(initialdir=downloads_folder, title="Wählen Sie den Ordner mit den DICOM-Dateien")
if source_folder: # Prüfe, ob ein Ordner ausgewählt wurde
print(f"Ausgewähltes Verzeichnis: {source_folder}")
print("Vor dem Aufruf von on_folder_selected") # Debugging-Ausgabe
self.on_folder_selected(source_folder) # Ruf den Callback mit dem ausgewählten Ordner auf
print("Nach dem Aufruf von on_folder_selected") # Debugging-Ausgabe
else:
print("Kein Ordner ausgewählt.")
def close(self):
self.root.destroy()
def show_discrepancy_dialog(self, message):
dialog = JaAbbruchDialog(self.root, "Unstimmigkeiten gefunden", message, self.on_app_close, self.transfer_folder)
response = dialog.show()
return response
def show_confirm_keep_original_dialog(self, tomedo_data, original_data):
"""Zeigt einen Bestätigungsdialog, wenn Original-Daten behalten werden sollen"""
dialog = ConfirmKeepOriginalDialog(self.root, self.on_app_close, self.transfer_folder, tomedo_data, original_data)
response = dialog.show()
return response
def ask_for_more(self, message):
dialog = JaNeinAbbruchDialog(self.root, "Weitere DICOM Dateien einlesen?", message, self.on_app_close, self.transfer_folder)
response = dialog.show()
if response: # Wenn die Antwort True ist, also der Benutzer mit Ja antwortet
print(response)
# Öffne standardmäßig den Downloads-Ordner
downloads_folder = os.path.join(os.path.expanduser('~'), 'Downloads')
if not os.path.exists(downloads_folder):
downloads_folder = os.path.expanduser('~') # Fallback auf Home-Verzeichnis
source_folder = filedialog.askdirectory(initialdir=downloads_folder, title="Wählen Sie den Ordner mit den DICOM-Dateien")
if not source_folder: # Prüfen, ob der Benutzer den Vorgang abgebrochen hat, ohne einen Ordner auszuwählen
return False # Sie können hier entscheiden, ob False oder eine andere Kennzeichnung zurückgegeben wird
return response, source_folder
else:
print(response)
return response, None
def on_app_close(self):
print("App wird beendet...")
# Beende den Tkinter Event-Loop und schließe alle Fenster
try:
self.root.quit()
except Exception as e:
print(f"Fehler beim Beenden des Tkinter Event-Loops: {e}")
# Lösche den Transferordner
try:
shutil.rmtree(self.transfer_folder)
print(f"Transferordner {self.transfer_folder} wurde gelöscht.")
except Exception as e:
print(f"Fehler beim Löschen des Transferordners: {e}")
# Datei existiert nicht, keine Aktion erforderlich
def upload_progress(self, incremental_progress, total_files):
if incremental_progress == 0:
self.progress['value'] = 0
# Initialisierung bei Beginn des Upload-Prozesses
print("Initialisiere Fortschrittsanzeige auf 0")
else:
self.progress['value'] += incremental_progress
new_value = self.progress['value']
print(f"Aktualisiere Fortschritt: {new_value}/{total_files}")
print(f"Aktueller Wert der Progressbar: {new_value - incremental_progress}")
print(f"Neuer Wert der Progressbar: {new_value}")
self.progress['maximum'] = total_files
self.root.update_idletasks()
async def upload_success(self, message):
try:
# Angenommen, wir führen eine Aktion aus, die fehlschlagen könnte
print("Upload erfolgreich:", message) # Beispiel: Drucke die Erfolgsmeldung in der Konsole
# Planen Sie GUI-Updates im Hauptthread
#self.root.after(0, self.show_success_message, message)
except Exception as e:
print(f"Fehler in upload_success: {e}")
# Planen Sie die Fehlermeldung im Hauptthread, um Thread-Sicherheit zu gewährleisten
#self.root.after(0, self.show_error_message, str(e))
def show_success_message(self, message):
messagebox.showinfo("Upload Erfolg", message)
def show_error_message(self, message):
messagebox.showerror("Fehler", message)
def disable_browse_button(self):
"""Deaktiviert den Durchsuchen Button."""
self.browse_button.config(state=tk.DISABLED)
def enable_browse_button(self):
"""Aktiviert den Durchsuchen Button."""
self.browse_button.config(state=tk.NORMAL)
def bind_shortcuts(self):
self.root.bind('<Command-comma>', lambda event: self.open_settings_dialog())
def open_settings_dialog(self):
# Erstellt eine Instanz der SettingsDialog Klasse
SettingsDialog(self.root, self.config)
class JaAbbruchDialog(tk.Toplevel):
def __init__(self, parent, title, message, on_app_close, transfer_folder=None):
super().__init__(parent)
self.result = None
self.on_app_close = on_app_close
self.transfer_folder = transfer_folder
self.title(title)
self.geometry("900x500") # Größeres Fenster für bessere Lesbarkeit
self.minsize(850, 480) # Minimale Größe erhöht
# Hauptframe für besseres Layout
main_frame = tk.Frame(self)
main_frame.pack(fill=tk.BOTH, expand=True, padx=40, pady=30)
italic_font = font.Font(family="Helvetica", size=14, slant="italic")
bold_font = font.Font(family="Helvetica", size=15, weight="bold")
normal_font = font.Font(family="Helvetica", size=14)
header_font = font.Font(family="Helvetica", size=17, weight="bold")
# Titel
title_label = tk.Label(main_frame, text=title, font=header_font)
title_label.pack(pady=(0, 30))
# Erwartete Daten - in einem Frame mit Hintergrund
expected_frame = tk.Frame(main_frame, bg='#ffffff', relief=tk.SUNKEN, bd=1)
expected_frame.pack(fill=tk.X, pady=(0, 20))
expected_inner = tk.Frame(expected_frame, bg='#ffffff')
expected_inner.pack(fill=tk.BOTH, expand=True, padx=20, pady=15)
tk.Label(expected_inner, text="Erwartete Daten (Tomedo):", font=italic_font,
bg='#ffffff', fg='#0066cc', anchor="w").pack(pady=(0, 8), fill=tk.X)
expected_label = tk.Label(expected_inner, text=message.split('\n\n')[0],
font=normal_font, justify=tk.LEFT, wraplength=800,
bg='#ffffff', fg='#000000', anchor="w")
expected_label.pack(pady=(0, 0), fill=tk.X)
# Gefundene Daten - in einem Frame mit Hintergrund
found_frame = tk.Frame(main_frame, bg='#ffffff', relief=tk.SUNKEN, bd=1)
found_frame.pack(fill=tk.X, pady=(0, 30))
found_inner = tk.Frame(found_frame, bg='#ffffff')
found_inner.pack(fill=tk.BOTH, expand=True, padx=20, pady=15)
tk.Label(found_inner, text="Gefundene Daten (DICOM):", font=italic_font,
bg='#ffffff', fg='#cc6600', anchor="w").pack(pady=(0, 8), fill=tk.X)
found_label = tk.Label(found_inner, text=message.split('\n\n')[1],
font=normal_font, justify=tk.LEFT, wraplength=800,
bg='#ffffff', fg='#000000', anchor="w")
found_label.pack(pady=(0, 0), fill=tk.X)
# Frage
question_label = tk.Label(main_frame,
text="Welche Daten sollen verwendet werden?",
font=bold_font, wraplength=800)
question_label.pack(pady=(0, 25))
# Button-Frame mit besserem Layout - Standard macOS Buttons
btn_frame = tk.Frame(main_frame)
btn_frame.pack(pady=15)
# Standard macOS Buttons (ttk.Button für besseres macOS-Aussehen) - breiter für bessere Lesbarkeit
yes_btn = create_macos_button(btn_frame, text="Tomedo-Daten übernehmen",
command=self.on_yes, width=30)
yes_btn.pack(side=tk.LEFT, padx=10)
no_btn = create_macos_button(btn_frame, text="Original-Daten behalten",
command=self.on_no, width=30)
no_btn.pack(side=tk.LEFT, padx=10)
cancel_btn = create_macos_button(btn_frame, text="Abbruch",
command=self.on_cancel, width=20)
cancel_btn.pack(side=tk.LEFT, padx=10)
self.center_window()
def center_window(self):
self.update_idletasks() # Aktualisiere das Layout, um die Fenstergröße zu erhalten
dialog_width = self.winfo_width()
dialog_height = self.winfo_height()
# Position des Hauptfensters
parent_x = self.master.winfo_x()
parent_y = self.master.winfo_y()
parent_width = self.master.winfo_width()
parent_height = self.master.winfo_height()
# Berechne die Position für das zentrierte Dialogfenster
center_x = int(parent_x + (parent_width - dialog_width) / 2)
center_y = int(parent_y + (parent_height - dialog_height) / 2)
self.geometry(f"{dialog_width}x{dialog_height}+{center_x}+{center_y}")
def on_yes(self):
self.result = True # Tomedo-Daten übernehmen
self.destroy()
def on_no(self):
self.result = False # Original-Daten behalten
self.destroy()
def on_cancel(self):
self.result = None # Abbruch
# Lösche Transfer-Ordner bei Abbruch
if self.transfer_folder:
self._delete_transfer_folder()
self.on_app_close() # Rufe on_app_close auf
self.destroy()
def on_close(self):
self.result = None # Abbruch
# Lösche Transfer-Ordner bei Abbruch
if self.transfer_folder:
self._delete_transfer_folder()
self.on_app_close() # Rufe on_app_close auf
self.destroy()
def _delete_transfer_folder(self):
"""Löscht den Transfer-Ordner"""
import shutil
try:
if os.path.exists(self.transfer_folder):
shutil.rmtree(self.transfer_folder)
print(f"Transferordner {self.transfer_folder} wurde gelöscht.")
except Exception as e:
print(f"Fehler beim Löschen des Transferordners: {e}")
def show(self):
# Binden des Schließ-Events des Fensters an on_close
self.protocol("WM_DELETE_WINDOW", self.on_close)
self.wait_window(self)
return self.result
class ConfirmKeepOriginalDialog(tk.Toplevel):
"""Bestätigungsdialog, wenn Original-Daten behalten werden sollen"""
def __init__(self, parent, on_app_close, transfer_folder=None, tomedo_data="", original_data=""):
super().__init__(parent)
self.result = None
self.on_app_close = on_app_close
self.transfer_folder = transfer_folder
self.title("Bestätigung")
self.geometry("900x620") # Größeres Fenster für vollständige Datenanzeige und bessere Lesbarkeit
self.minsize(850, 600) # Minimale Größe erhöht
main_frame = tk.Frame(self)
main_frame.pack(fill=tk.BOTH, expand=True, padx=40, pady=30)
bold_font = font.Font(family="Helvetica", size=15, weight="bold")
normal_font = font.Font(family="Helvetica", size=14)
italic_font = font.Font(family="Helvetica", size=14, slant="italic")
header_font = font.Font(family="Helvetica", size=17, weight="bold")
# Titel
title_label = tk.Label(main_frame, text="Bestätigung", font=header_font)
title_label.pack(pady=(0, 20))
# Warnung
warning_label = tk.Label(main_frame,
text="⚠️ Warnung",
font=bold_font, fg='#cc6600')
warning_label.pack(pady=(0, 20))
# Erwartete Daten (Tomedo) - in einem Frame mit Hintergrund (wie im ersten Dialog)
tomedo_frame = tk.Frame(main_frame, bg='#ffffff', relief=tk.SUNKEN, bd=1)
tomedo_frame.pack(fill=tk.X, pady=(0, 20))
tomedo_inner = tk.Frame(tomedo_frame, bg='#ffffff')
tomedo_inner.pack(fill=tk.BOTH, expand=True, padx=20, pady=15)
tk.Label(tomedo_inner, text="Erwartete Daten (Tomedo):", font=italic_font,
bg='#ffffff', fg='#0066cc', anchor="w").pack(pady=(0, 8), fill=tk.X)
tomedo_label = tk.Label(tomedo_inner, text=tomedo_data,
font=normal_font, justify=tk.LEFT, wraplength=800,
bg='#ffffff', fg='#000000', anchor="w")
tomedo_label.pack(pady=(0, 0), fill=tk.X)
# Gefundene Daten (DICOM) - in einem Frame mit Hintergrund (wie im ersten Dialog)
original_frame = tk.Frame(main_frame, bg='#ffffff', relief=tk.SUNKEN, bd=1)
original_frame.pack(fill=tk.X, pady=(0, 25))
original_inner = tk.Frame(original_frame, bg='#ffffff')
original_inner.pack(fill=tk.BOTH, expand=True, padx=20, pady=15)
tk.Label(original_inner, text="Gefundene Daten (DICOM):", font=italic_font,
bg='#ffffff', fg='#cc6600', anchor="w").pack(pady=(0, 8), fill=tk.X)
original_label = tk.Label(original_inner, text=original_data,
font=normal_font, justify=tk.LEFT, wraplength=800,
bg='#ffffff', fg='#000000', anchor="w")
original_label.pack(pady=(0, 0), fill=tk.X)
# Frage
question_label = tk.Label(main_frame,
text="Sind Sie sicher, dass Sie die Original-Daten behalten möchten?",
font=bold_font, wraplength=800, justify=tk.CENTER)
question_label.pack(pady=(0, 10))
info_label = tk.Label(main_frame,
text="Die Tomedo-Daten sind der Standard und sollten normalerweise verwendet werden.",
font=normal_font, wraplength=800, justify=tk.CENTER, fg='#666666')
info_label.pack(pady=(0, 20))
# Button-Frame
btn_frame = tk.Frame(main_frame)
btn_frame.pack(pady=10)
# Buttons (macOS-Style) - breiter für bessere Lesbarkeit
tomedo_btn = create_macos_button(btn_frame, text="Tomedo-Daten verwenden",
command=self.on_use_tomedo, width=28)
tomedo_btn.pack(side=tk.LEFT, padx=8)
keep_btn = create_macos_button(btn_frame, text="Original behalten",
command=self.on_keep_original, width=24)
keep_btn.pack(side=tk.LEFT, padx=8)
cancel_btn = create_macos_button(btn_frame, text="Abbruch",
command=self.on_cancel, width=18)
cancel_btn.pack(side=tk.LEFT, padx=8)
self.center_window()
def center_window(self):
self.update_idletasks()
dialog_width = self.winfo_width()
dialog_height = self.winfo_height()
parent_x = self.master.winfo_x()
parent_y = self.master.winfo_y()
parent_width = self.master.winfo_width()
parent_height = self.master.winfo_height()
center_x = int(parent_x + (parent_width - dialog_width) / 2)
center_y = int(parent_y + (parent_height - dialog_height) / 2)
self.geometry(f"{dialog_width}x{dialog_height}+{center_x}+{center_y}")
def on_use_tomedo(self):
self.result = True # Tomedo-Daten verwenden
self.destroy()
def on_keep_original(self):
self.result = False # Original-Daten behalten
self.destroy()
def on_cancel(self):
self.result = None # Abbruch
# Lösche Transfer-Ordner bei Abbruch
if self.transfer_folder:
self._delete_transfer_folder()
self.on_app_close()
self.destroy()
def on_close(self):
self.result = None # Abbruch
# Lösche Transfer-Ordner bei Abbruch
if self.transfer_folder:
self._delete_transfer_folder()
self.on_app_close()
self.destroy()
def _delete_transfer_folder(self):
"""Löscht den Transfer-Ordner"""
try:
if os.path.exists(self.transfer_folder):
shutil.rmtree(self.transfer_folder)
print(f"Transferordner {self.transfer_folder} wurde gelöscht.")
except Exception as e:
print(f"Fehler beim Löschen des Transferordners: {e}")
def show(self):
self.protocol("WM_DELETE_WINDOW", self.on_close)
self.wait_window(self)
return self.result
class JaNeinAbbruchDialog(tk.Toplevel):
def __init__(self, parent, title, message, on_app_close, transfer_folder=None):
super().__init__(parent)
self.result = None
self.on_app_close = on_app_close
self.transfer_folder = transfer_folder
self.message = message # Speichere die Nachricht
self.title(title)
self.geometry("400x175") # Größe des Dialogs
tk.Label(self, text=self.message).pack(pady=20)
btn_frame = tk.Frame(self)
btn_frame.pack(pady=10)
# Buttons (macOS-Style)
ja_btn = create_macos_button(btn_frame, text="Ja", command=self.on_ja)
ja_btn.pack(side=tk.LEFT, padx=10, pady=20)
nein_btn = create_macos_button(btn_frame, text="Nein", command=self.on_nein)
nein_btn.pack(side=tk.LEFT, padx=10, pady=20)
abbruch_btn = create_macos_button(btn_frame, text="Abbruch", command=self.on_abbruch)
abbruch_btn.pack(side=tk.LEFT, padx=10, pady=20)
self.center_window()
def center_window(self):
self.update_idletasks() # Aktualisiere das Layout, um die Fenstergröße zu erhalten
dialog_width = self.winfo_width()
dialog_height = self.winfo_height()
# Position des Hauptfensters
parent_x = self.master.winfo_x()
parent_y = self.master.winfo_y()
parent_width = self.master.winfo_width()
parent_height = self.master.winfo_height()
# Berechne die Position für das zentrierte Dialogfenster
center_x = int(parent_x + (parent_width - dialog_width) / 2)
center_y = int(parent_y + (parent_height - dialog_height) / 2)
self.geometry(f"{dialog_width}x{dialog_height}+{center_x}+{center_y}")
def on_ja(self):
self.result = True
self.destroy()
def on_nein(self):
self.result = False
self.destroy()
def on_abbruch(self):
self.result = False
# Lösche Transfer-Ordner bei Abbruch
if self.transfer_folder:
self._delete_transfer_folder()
self.on_app_close() # Rufe on_app_close auf
self.destroy()
def on_close(self):
self.result = False
# Lösche Transfer-Ordner bei Abbruch
if self.transfer_folder:
self._delete_transfer_folder()
self.on_app_close() # Rufe on_app_close auf
self.destroy()
def _delete_transfer_folder(self):
"""Löscht den Transfer-Ordner"""
try:
if os.path.exists(self.transfer_folder):
shutil.rmtree(self.transfer_folder)
print(f"Transferordner {self.transfer_folder} wurde gelöscht.")
except Exception as e:
print(f"Fehler beim Löschen des Transferordners: {e}")
def show(self):
# Binden des Schließ-Events des Fensters an on_close
self.protocol("WM_DELETE_WINDOW", self.on_close)
self.wait_window(self)
return self.result