# -*- coding: utf-8 -*- """ Диалози за съобщения, центрирани спрямо прозореца на приложението (parent), а не спрямо физическия екран. """ import tkinter as tk from tkinter import ttk def _center_on_parent(dialog, parent): """Поставя диалога в центъра на parent (размер и позиция на приложението).""" if parent is None: return dialog.update_idletasks() parent.update_idletasks() w = dialog.winfo_reqwidth() h = dialog.winfo_reqheight() rw = parent.winfo_width() rh = parent.winfo_height() rx = parent.winfo_rootx() ry = parent.winfo_rooty() x = rx + max(0, (rw - w) // 2) y = ry + max(0, (rh - h) // 2) dialog.geometry(f"+{x}+{y}") def _dialog(parent, title, message, dialog_type="info", ask_yes_no=False): """ Показва модален диалог (Toplevel), центриран спрямо parent. dialog_type: "info" | "warning" | "error" ask_yes_no: ако True, бутони Да/Не и връща True/False. """ root = parent.winfo_toplevel() if parent else tk._default_root d = tk.Toplevel(root) d.title(title) d.transient(parent or root) d.resizable(False, False) # рамка с отстъп f = ttk.Frame(d, padding=16) f.pack(fill=tk.BOTH, expand=True) # иконка + текст (опционално различни цветове за error/warning) msg_label = ttk.Label(f, text=message, wraplength=400, justify=tk.LEFT) msg_label.pack(anchor=tk.W, fill=tk.X, pady=(0, 12)) result = [None] def ok(): result[0] = True d.destroy() def no(): result[0] = False d.destroy() btn_frame = ttk.Frame(f) btn_frame.pack(anchor=tk.E) if ask_yes_no: ttk.Button(btn_frame, text="Да", command=ok).pack(side=tk.LEFT, padx=4) ttk.Button(btn_frame, text="Не", command=no).pack(side=tk.LEFT, padx=4) else: ttk.Button(btn_frame, text="OK", command=ok).pack(side=tk.LEFT, padx=4) d.protocol("WM_DELETE_WINDOW", no if ask_yes_no else ok) if parent: d.after_idle(lambda: _center_on_parent(d, parent)) d.grab_set() d.focus_set() d.wait_window() return result[0] if ask_yes_no else None def showinfo(title, message, parent=None): _dialog(parent, title, message, "info", ask_yes_no=False) def showwarning(title, message, parent=None): _dialog(parent, title, message, "warning", ask_yes_no=False) def showerror(title, message, parent=None): _dialog(parent, title, message, "error", ask_yes_no=False) def askyesno(title, message, parent=None): return _dialog(parent, title, message, "info", ask_yes_no=True) is True