Sein Befund "und beim steuertool fehlt das theam in genze oder wird nicht durch die automatik gesetzt" "nur die einstellunden hilfe leiste die ist noch hell und der icon und titel leiste auch" Er hatte recht, und zwar wortwoertlich: dieses Programm lief im Tk-Standard, mit dreimal fest eingetragenem foreground="black". Es gab hier gar keine theme.py. Gebaut theme.py aus dem Rechnungstool uebernommen und dabei von config.py geloest - eine Datei, die in BEIDEN Programmen liegt, darf nichts aus einem der beiden importieren. Beim ersten Uebernehmen flog sie genau daran beim Import auseinander. Die Einstellungen liegen hier in der Journal-Tabelle, nicht in einer config.json. _einstellungen() ist die Bruecke: etwas mit .get() und []=, wie hinweis.py und theme.py es erwarten. Menueleiste aus menueleiste.py statt tk.Menu - ein natives Menue laesst sich unter Windows nicht einfaerben, das war der letzte helle Rest. Treeview-Stil in theme.py ergaenzt (ttk zeichnet Listen nicht ueber den Grundstil), Reiter schmaler, damit alle zwoelf Monatsnamen lesbar bleiben. Die Summenleisten in gui_monat.py holen ihre Farben jetzt vom Fenster statt sie fest zu tragen - sie waren ein weisser Block unten im dunklen Bild. Logo und Fenstersymbol werden fuer die dunkle Darstellung aufgehellt. ⚠️ Altfehler behoben: die Meldung des Rechnungstools stand nie pruef_wache lief mal gruen und mal rot - je nachdem, wann er hinsah. Das war kein Wackler im Pruefstand, sondern sein Symptom: meldet das Rechnungstool eine neue Rechnung, laeuft sofort das Einlesen an, und dessen Ergebnis landete in derselben Zeile. Der Benutzer sah NIE, dass etwas hereingekommen war. melde() kennt jetzt einen Vorrang in Sekunden; die Meldung des Rechnungstools bekommt sechs. Dreimal hintereinander stabil gruen. Ein wackelnder Pruefstand ist keine Nebensache, die man wegdrueckt. AUFGABE_STEUERSAETZE_DYNAMISCH.md Seine naechste Ansage notiert: die festen Saetze sollen raus, dynamisch per Tabelle wie im Rechnungstool. Mit dem, worauf dabei zu achten ist - ein Satz gilt ab einem DATUM, und die Saetze bereits erfasster Buchungen bleiben stehen (§ 147 AO). Fassung 1.9.0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
183 lines
5.6 KiB
Python
183 lines
5.6 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"
|
|
"und beim steuertool fehlt das theam in genze oder wird nicht durch die
|
|
automatik gesetzt"
|
|
|
|
Er hatte recht: dieses Programm hatte ueberhaupt kein Theme - es lief im
|
|
Tk-Standard, mit dreimal fest eingetragenem foreground="black".
|
|
|
|
GEPRUEFT WIRD DREIERLEI
|
|
|
|
1. Die Einstellung wirkt. "hell" ist hell, "dunkel" ist dunkel, "auto" folgt
|
|
Windows.
|
|
|
|
2. Beim Umschalten bleibt der Stand stehen - Jahr und Suchfeld.
|
|
|
|
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 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)
|
|
|
|
# Auf einer KOPIE des Programms arbeiten: der Datenordner liegt aus der Quelle
|
|
# heraus neben app.py (ablage.py), also legt eine Kopie im Temp-Ordner auch ein
|
|
# eigenes Journal an. Das echte Journal des Betriebs wird nicht angefasst -
|
|
# hier wird eine Einstellung geschrieben, und die gehoert nicht in seine Daten.
|
|
tmp = tempfile.mkdtemp(prefix="darstellung_")
|
|
prog = os.path.join(tmp, "programm")
|
|
os.makedirs(prog)
|
|
for name in os.listdir(QUELLE):
|
|
if name.endswith(".py"):
|
|
shutil.copy(os.path.join(QUELLE, name), os.path.join(prog, name))
|
|
for name in ("assets",):
|
|
if os.path.isdir(os.path.join(QUELLE, name)):
|
|
shutil.copytree(os.path.join(QUELLE, name), os.path.join(prog, name))
|
|
sys.path.insert(0, prog)
|
|
os.chdir(prog)
|
|
|
|
import app as A # noqa: E402
|
|
import theme # noqa: E402
|
|
|
|
f = A.App()
|
|
|
|
|
|
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")
|
|
|
|
# ---- Stand, der den Wechsel ueberleben muss ----------------------------
|
|
f.jahr.set(2025)
|
|
f.suche.set("Muster")
|
|
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
|
|
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.jahr.get() == 2025,
|
|
f"nach dem Wechsel steht das gewaehlte Jahr noch da ({f.jahr.get()})")
|
|
pruefe(f.suche.get() == "Muster",
|
|
f"und der Suchbegriff ({f.suche.get()!r})")
|
|
|
|
# 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"
|
|
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"
|
|
f.destroy()
|
|
f = A.App()
|
|
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")
|