diff --git a/app.py b/app.py index 32fe38f..a921b85 100644 --- a/app.py +++ b/app.py @@ -512,8 +512,19 @@ class RechnungsApp(ThemeMixin, MeldungMixin, KorrekturMixin, EinstellungenMixin, except Exception: # noqa: BLE001 - dann eben das erste Blatt pass + # Fremde Fenster stehen lassen! Ein tk.Toplevel IST ein Kind des + # Hauptfensters - der offene Darstellungsdialog wurde hier bisher + # mitgeloescht, und die Zeile danach fasste eine Leiche an + # ("invalid command name .!toplevel"). Gefunden am 07.09.2026 von der + # Pruefkette, mit dem echten Bedienweg gemessen: Klick auf "Dunkel" + # -> Farbe wechselt, Fenster ist weg, Traceback im Log. + # + # Der Pruefstand hat es nicht gefunden, weil er cfg["darstellung"] von + # Hand setzte und _oberflaeche_neu() direkt rief - also alles ausser + # dem Weg, den ein Mensch geht. for kind in self.winfo_children(): - kind.destroy() + if not isinstance(kind, tk.Toplevel): + kind.destroy() self.flaeche = None self._text_zellen = [] @@ -846,8 +857,6 @@ class RechnungsApp(ThemeMixin, MeldungMixin, KorrekturMixin, EinstellungenMixin, def _fenstersymbol(self): """Das Programmsymbol auf das Fenster legen.""" return wasserzeichen.symbol_setzen(self, dunkel=getattr(self, "_dark_mode", False)) - print("[symbol] assets/programm.ico nicht gefunden") - return False def _hinweis_wenn_sichtbar(self, versuche=0): """Wartet, bis das Fenster gezeichnet ist, und fragt dann. diff --git a/pruef_darstellung.py b/pruef_darstellung.py index 3c076b6..260d444 100644 --- a/pruef_darstellung.py +++ b/pruef_darstellung.py @@ -189,6 +189,66 @@ pruefe(d.winfo_rooty() >= f.winfo_rooty() - 40, d.destroy() pumpen(0.3) +# ---- Der Dialog muss den Klick UEBERLEBEN ------------------------------- +# Gefunden am 07.09.2026 von der Pruefkette: _oberflaeche_neu() loeschte alle +# Kinder des Hauptfensters - und ein Toplevel IST ein Kind. Der offene Dialog +# wurde also beim ersten Klick mitgeloescht, die Zeile danach fasste eine +# Leiche an ("invalid command name .!toplevel"). +# +# Dieser Pruefstand hat es NICHT gefunden, weil er cfg["darstellung"] von Hand +# setzte. Hier wird jetzt der Radioknopf gedrueckt - derselbe Weg, den ein +# Mensch geht. +d = f.dlg_darstellung() +pumpen(1.0) + + +def radioknoepfe(fenster): + """Alle Radiobuttons unterhalb eines Fensters, mit ihrer Beschriftung.""" + treffer = [] + + def durchgehen(w): + for kind in w.winfo_children(): + if kind.winfo_class() == "TRadiobutton": + try: + treffer.append((str(kind.cget("text")), kind)) + except tk.TclError: + pass + durchgehen(kind) + + durchgehen(fenster) + return treffer + + +knoepfe = radioknoepfe(d) +pruefe(len(knoepfe) == len(theme.MODI), + f"der Dialog zeigt alle {len(theme.MODI)} Moeglichkeiten " + f"({[t for t, _ in knoepfe]})") + +ziel = next((w for t, w in knoepfe if t == theme.MODUS_NAMEN["dunkel"]), None) +pruefe(ziel is not None, "der Knopf 'Dunkel' ist da") +if ziel is not None: + ziel.invoke() # der echte Klick + pumpen(1.2) + pruefe(bool(d.winfo_exists()), + "der Dialog lebt nach dem Klick noch") + pruefe(f._dark_mode is True, + f"und die Darstellung ist umgestellt (Hintergrund {f.col_bg})") + # Und noch einmal, denn genau das war vorher unmoeglich: + hell = next((w for t, w in knoepfe if t == theme.MODUS_NAMEN["hell"]), None) + if hell is not None: + try: + hell.invoke() + pumpen(1.0) + pruefe(f._dark_mode is False, + "ein ZWEITER Klick im selben Dialog wirkt auch") + except tk.TclError as e: + pruefe(False, f"der zweite Klick scheiterte ({e})") +try: + d.destroy() +except tk.TclError: + pass +pumpen(0.3) + # ---- Zurueck auf automatisch -------------------------------------------- f.cfg["darstellung"] = "auto" config.save_config(f.cfg)