Seine Ansage "waere nun noch gut das mann in den einstellungen einstellen kann hell oder dunkel oder automatik das fehlt sollte eigendlich drin sein" Er hatte recht: beide Farbpaletten lagen laengst in theme.py, das Programm folgte aber starr dem Windows-Theme. Jetzt steht die Wahl unter Einstellungen -> Darstellung und wirkt SOFORT, nicht erst beim Neustart. Umschalten heisst neu bauen Die Farben stehen an ueber sechzig Stellen fest in den Widgets. Sie einzeln nachzuziehen hiesse, ein Verzeichnis aller eingefaerbten Widgets zu fuehren - und wer beim naechsten neuen Widget vergisst, es einzutragen, hat einen hellen Fleck im dunklen Fenster, den niemand mehr findet. Neu bauen kann nichts vergessen. ⚠️ Dabei gingen im ersten Versuch Kundenname und Rechnungsnummer verloren: die _build_-Methoden legen ihre StringVars SELBST an, nach dem Neubau standen leere da. Gesichert werden jetzt ALLE Tk-Variablen des Fensters, nicht eine gepflegte Auswahl - wer spaeter ein Feld hinzufuegt, muss nichts eintragen. Titelleiste, Symbol und Logo gehen mit Die Titelleiste gehoert Windows; sie folgt ueber DWMWA_USE_IMMERSIVE_DARK_MODE. _dark_titlebar konnte bisher nur DUNKEL und zeigt jetzt in beide Richtungen - vorher behielt man beim Wechsel auf hell eine schwarze Leiste ueber einem hellen Fenster. Sein Befund: "die svg fuer das dunkle heller machen weil die geht nun unter" und "icon musst wenn es dunkel ist mit aendern auf das hellere". Gemessen sind es zwei Farben: Petrol #004860 und ein fast schwarzes #181818 - letzteres liegt genau auf der Kachelfarbe #15171b. Umgestellt wird nur die HELLIGKEIT (L -> 1-L, gedeckelt bei 0.78), Farbton und Saettigung bleiben: sonst waere es nicht mehr sein Logo. Betrifft Wasserzeichen, Kopflogo und das Fenstersymbol; die aufgehellte ICO entsteht beim Bauen. menueleiste.py Die selbstgebaute Menueleiste ist jetzt eine eigene Datei und liegt in beiden Programmen gleich - das Steuerrechnungstool hatte noch das native tk.Menu, das sich unter Windows nicht einfaerben laesst. pruef_darstellung.py Prueft die drei Modi, dass beim Umschalten NICHTS verlorengeht, und dass danach kein Widget mehr eine Farbe der anderen Palette traegt - genau der helle Fleck, den man sonst nie wiederfindet. Nebenbei: die beiden Dauertimer melden beim Beenden kein "invalid command name ..._api_pumpe" mehr. Ein Log, in dem beim normalen Beenden immer zwei Fehler stehen, liest irgendwann niemand mehr. Fassung 1.8.0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
196 lines
6.2 KiB
Python
196 lines
6.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Pruefstand: hell, dunkel, automatisch - und nichts geht dabei verloren.
|
|
|
|
Sein Wortlaut vom 07.09.2026:
|
|
|
|
"waere nun noch gut das mann in den einstellungen einstellen kann hell
|
|
oder dunkel oder automatik das fehlt sollte eigendlich drin sein"
|
|
|
|
GEPRUEFT WIRD DREIERLEI
|
|
|
|
1. Die Einstellung wirkt. "hell" ist hell, "dunkel" ist dunkel, "auto" folgt
|
|
Windows.
|
|
|
|
2. Beim Umschalten bleibt jede Eingabe stehen. Das ist der Punkt, an dem es
|
|
beim Bauen schiefging: die Mengen der Leistungszeilen hatte ich einzeln
|
|
gesichert, Kundenname und Rechnungsnummer nicht - die _build_-Methoden
|
|
legen ihre Variablen selbst an, beim Neubau standen also leere da. Wer
|
|
waehrend einer halb getippten Rechnung auf dunkel stellt, darf sie nicht
|
|
verlieren.
|
|
|
|
3. NACH dem Wechsel traegt kein Widget mehr eine Farbe der anderen Palette.
|
|
Das ist die eigentliche Falle beim Umfaerben: ein einzelnes vergessenes
|
|
Label leuchtet hell im dunklen Fenster, und niemand findet die Stelle
|
|
wieder. Deshalb wird der ganze Widget-Baum abgegangen und mit den Farben
|
|
der jeweils ANDEREN Palette verglichen.
|
|
"""
|
|
import json
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
import time
|
|
import tkinter as tk
|
|
|
|
QUELLE = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, QUELLE)
|
|
|
|
fehler = []
|
|
|
|
|
|
def pruefe(bedingung, text):
|
|
zeile = (" OK | " if bedingung else "FEHLER | ") + text
|
|
kod = sys.stdout.encoding or "utf-8"
|
|
print(zeile.encode(kod, "replace").decode(kod))
|
|
if not bedingung:
|
|
fehler.append(text)
|
|
|
|
|
|
os.chdir(QUELLE)
|
|
os.environ["CAMPINGHOF_TEST"] = "1"
|
|
|
|
from tkinter import messagebox # noqa: E402
|
|
|
|
messagebox.askyesno = lambda *a, **k: True
|
|
for _n in ("showinfo", "showwarning", "showerror"):
|
|
setattr(messagebox, _n, lambda *a, **k: None)
|
|
|
|
import config # noqa: E402
|
|
|
|
# Auf einer Kopie arbeiten - die echte Konfiguration wird nicht angefasst.
|
|
tmp = tempfile.mkdtemp(prefix="darstellung_")
|
|
shutil.copy(os.path.join(QUELLE, "config.json"), os.path.join(tmp, "config.json"))
|
|
config.CONFIG_PATH = os.path.join(tmp, "config.json")
|
|
roh = json.load(open(config.CONFIG_PATH, encoding="utf-8"))
|
|
roh["nummer_eingerichtet"] = True
|
|
roh.pop("darstellung", None)
|
|
json.dump(roh, open(config.CONFIG_PATH, "w", encoding="utf-8"),
|
|
ensure_ascii=False, indent=2)
|
|
|
|
import app as A # noqa: E402
|
|
import theme # noqa: E402
|
|
|
|
f = A.RechnungsApp()
|
|
|
|
|
|
def pumpen(sekunden=1.0):
|
|
ende = time.time() + sekunden
|
|
while time.time() < ende:
|
|
f.update()
|
|
time.sleep(0.02)
|
|
|
|
|
|
pumpen(2.0)
|
|
|
|
# ---- Ohne Einstellung: automatisch --------------------------------------
|
|
pruefe(theme.modus(f.cfg) == "auto",
|
|
f"ohne Eintrag gilt 'auto' ({theme.modus(f.cfg)!r})")
|
|
pruefe(f._dark_mode == theme.windows_dark_mode(),
|
|
"und folgt damit dem Windows-Theme")
|
|
|
|
# ---- Eingaben, die den Wechsel ueberleben muessen ------------------------
|
|
f.k_vorname.set("Erika")
|
|
f.k_name.set("Mustermann")
|
|
f.k_strasse.set("Musterweg 12")
|
|
f.k_plzort.set("04416 Markkleeberg")
|
|
f.r_nummer.set("2026-099")
|
|
f.r_anreise.set("01.09.2026")
|
|
erste = sorted(f.anzahl_vars)[0]
|
|
f.anzahl_vars[erste].set("3")
|
|
pumpen(0.5)
|
|
|
|
|
|
def farben(dunkel):
|
|
"""Die Palette der einen oder anderen Darstellung, als Menge."""
|
|
merker = f._dark_mode
|
|
f.cfg["darstellung"] = "dunkel" if dunkel else "hell"
|
|
f._apply_theme()
|
|
satz = {getattr(f, n).lower() for n in dir(f)
|
|
if n.startswith("col_") and isinstance(getattr(f, n), str)}
|
|
f._dark_mode = merker
|
|
return satz
|
|
|
|
|
|
HELL = farben(False)
|
|
DUNKEL = farben(True)
|
|
# Was in BEIDEN Paletten vorkommt, taugt nicht als Beweis.
|
|
NUR_HELL = HELL - DUNKEL
|
|
NUR_DUNKEL = DUNKEL - HELL
|
|
|
|
|
|
def fremdfarben(verboten):
|
|
"""Alle Widgets, die eine Farbe der falschen Palette tragen."""
|
|
treffer = []
|
|
|
|
def durchgehen(w):
|
|
for kind in w.winfo_children():
|
|
for eigenschaft in ("bg", "background", "fg", "foreground"):
|
|
try:
|
|
wert = str(kind.cget(eigenschaft)).lower()
|
|
except tk.TclError:
|
|
continue
|
|
if wert in verboten:
|
|
treffer.append((str(kind), eigenschaft, wert))
|
|
durchgehen(kind)
|
|
|
|
durchgehen(f)
|
|
return treffer
|
|
|
|
|
|
# ---- Die drei Modi ------------------------------------------------------
|
|
for wunsch, soll_dunkel in (("hell", False), ("dunkel", True)):
|
|
f.cfg["darstellung"] = wunsch
|
|
config.save_config(f.cfg)
|
|
f._oberflaeche_neu()
|
|
pumpen(0.8)
|
|
|
|
pruefe(f._dark_mode == soll_dunkel,
|
|
f"'{wunsch}' zeichnet {'dunkel' if soll_dunkel else 'hell'} "
|
|
f"(Hintergrund {f.col_bg})")
|
|
|
|
# Nichts darf verlorengehen.
|
|
pruefe(f.k_name.get() == "Mustermann",
|
|
f"nach dem Wechsel steht der Kundenname noch da ({f.k_name.get()!r})")
|
|
pruefe(f.r_nummer.get() == "2026-099",
|
|
f"und die Rechnungsnummer ({f.r_nummer.get()!r})")
|
|
pruefe(f.k_plzort.get() == "04416 Markkleeberg",
|
|
f"und die Anschrift ({f.k_plzort.get()!r})")
|
|
pruefe(f.r_anreise.get() == "01.09.2026",
|
|
f"und das Anreisedatum ({f.r_anreise.get()!r})")
|
|
pruefe(f.anzahl_vars.get(erste) is not None
|
|
and f.anzahl_vars[erste].get() == "3",
|
|
"und die eingetragene Menge in der Leistungszeile")
|
|
|
|
# Kein Rest der anderen Palette.
|
|
reste = fremdfarben(NUR_DUNKEL if not soll_dunkel else NUR_HELL)
|
|
pruefe(not reste,
|
|
f"in '{wunsch}' ist keine Farbe der anderen Darstellung "
|
|
f"uebrig ({reste[:3]})")
|
|
|
|
# ---- Zurueck auf automatisch --------------------------------------------
|
|
f.cfg["darstellung"] = "auto"
|
|
config.save_config(f.cfg)
|
|
f._oberflaeche_neu()
|
|
pumpen(0.8)
|
|
pruefe(f._dark_mode == theme.windows_dark_mode(),
|
|
"'auto' folgt wieder dem Windows-Theme")
|
|
|
|
# ---- Und die Einstellung ueberlebt den Neustart -------------------------
|
|
f.cfg["darstellung"] = "hell"
|
|
config.save_config(f.cfg)
|
|
f.destroy()
|
|
f = A.RechnungsApp()
|
|
pumpen(2.0)
|
|
pruefe(f._dark_mode is False,
|
|
"die Einstellung steht beim naechsten Start wieder da")
|
|
|
|
try:
|
|
f.destroy()
|
|
except Exception: # noqa: BLE001
|
|
pass
|
|
shutil.rmtree(tmp, ignore_errors=True)
|
|
|
|
if fehler:
|
|
print(f"ROT | {len(fehler)} Punkt(e) nicht erfuellt")
|
|
sys.exit(1)
|
|
print("GRUEN | Hell, dunkel und automatisch wirken - ohne Datenverlust")
|