Logo Das Programmlogo steht jetzt klein neben "powered by ravokk" - dort sitzt die Kennung des Werkzeugs, nicht die des Kunden. Eine eigene Kopfzeile hat dieses Programm nicht; oben sind die Reiter. bauen.py Der Weg von der Quelle zur Setup-Datei war eine Folge von Befehlen, die jemand von Hand eintippen musste. Wer einen Schritt vergisst, liefert eine Setup-Datei mit einer alten EXE aus - und sieht es ihr nicht an. Genau das ist heute passiert. Jetzt ist es ein Befehl, die Nummer kommt aus version.py, und am Ende stehen die SHA256-Summen fuer den Release-Text. pruef_start_exe.py Prueft, was kein anderer Pruefstand prueft: ob die GEBAUTE EXE ein sichtbares Fenster zeigt. Alle uebrigen fahren das Programm aus der Quelle, dort trat der Fehler nie auf. "Der Prozess laeuft" beweist dabei nichts - er lief ja, waehrend nichts zu sehen war. Aufgeraeumt "Rechnung Campinghof.exe" ist weg; gebaute Dateien gehoeren ins Release, nicht ins Repo. Die .spec-Dateien dagegen schon: ohne sie kann niemand die EXE nachbauen, die der Updater ausliefert. Fassung 1.7.0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
106 lines
3.8 KiB
Python
106 lines
3.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Das Programmlogo - als Fenstersymbol und als blasses Wasserzeichen.
|
|
|
|
WOHER DAS BILD KOMMT
|
|
--------------------
|
|
Die Quelle ist die SVG aus dem Entwurf (`assets/programm_logo.svg`). Sie wird
|
|
BEIM BAUEN einmal in 512 Pixel gerendert (`assets/programm_logo.png`) und in
|
|
eine `programm.ico` fuer Windows umgesetzt. Hier zur Laufzeit wird nur noch
|
|
skaliert.
|
|
|
|
Warum nicht direkt aus der SVG zeichnen? Weil dafuer `svglib` und `lxml` mit in
|
|
die EXE muessten - und bis 512 Pixel ist das Ergebnis pixelgenau dasselbe. Wird
|
|
das Wasserzeichen je groesser gebraucht, gehoert das umgestellt.
|
|
|
|
Warum ueberhaupt eine ICO? Weil Windows das Symbol einer EXE als Ressource in
|
|
der Datei erwartet, und dieses Format ist ICO. Das gilt fuer jede Sprache, nicht
|
|
nur fuer Python - eine SVG kann Windows dort nicht verwenden.
|
|
|
|
Diese Datei liegt in BEIDEN Programmen gleich. Wer sie aendert, kopiert sie
|
|
hinueber.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import tkinter as tk
|
|
|
|
_lager = {} # (fenster, groesse, deckkraft) -> PhotoImage
|
|
|
|
|
|
def _ordner():
|
|
"""Alle Orte, an denen die Bilder liegen koennen - Quelle wie EXE."""
|
|
hier = os.path.dirname(os.path.abspath(__file__))
|
|
aus_exe = getattr(sys, "_MEIPASS", "")
|
|
neben_exe = os.path.dirname(os.path.abspath(sys.executable)) \
|
|
if getattr(sys, "frozen", False) else ""
|
|
return [p for p in (aus_exe, neben_exe, hier) if p]
|
|
|
|
|
|
def pfad(name):
|
|
"""Voller Pfad zu einer Datei in assets/ - oder ''."""
|
|
for basis in _ordner():
|
|
p = os.path.join(basis, "assets", name)
|
|
if os.path.exists(p):
|
|
return p
|
|
return ""
|
|
|
|
|
|
def symbol_setzen(fenster, melden=print):
|
|
"""Das Programmsymbol auf ein Fenster legen. True bei Erfolg.
|
|
|
|
Die EXE traegt es ohnehin - das Fenster aber nicht von selbst. Ohne das
|
|
steht in der Titelleiste das nackte Tk-Symbol, obwohl die Datei ein eigenes
|
|
hat.
|
|
"""
|
|
p = pfad("programm.ico")
|
|
if not p:
|
|
melden("[symbol] assets/programm.ico nicht gefunden")
|
|
return False
|
|
try:
|
|
fenster.iconbitmap(default=p)
|
|
return True
|
|
except Exception as e: # noqa: BLE001 - ohne Symbol laeuft es weiter
|
|
melden(f"[symbol] konnte nicht gesetzt werden: {e}")
|
|
return False
|
|
|
|
|
|
def hole(groesse=240, deckkraft=0.06, master=None, melden=print):
|
|
"""Das Logo blass als PhotoImage - oder None.
|
|
|
|
`deckkraft` 0..1, klein halten. Ein Wasserzeichen, das man LIEST, stoert
|
|
beim Arbeiten; eines, das man ahnt, gehoert zum Programm.
|
|
|
|
`master` MUSS mitgegeben werden, wenn mehr als ein Tk-Fenster laeuft:
|
|
sonst gehoert das Bild dem falschen Fenster und Tk meldet spaeter, es
|
|
kenne es nicht.
|
|
"""
|
|
fenster = master if master is not None else tk._default_root
|
|
if fenster is None:
|
|
return None
|
|
schluessel = (id(fenster), groesse, round(deckkraft, 3))
|
|
if schluessel in _lager:
|
|
return _lager[schluessel]
|
|
p = pfad("programm_logo.png")
|
|
if not p:
|
|
melden("[wasserzeichen] assets/programm_logo.png nicht gefunden")
|
|
return None
|
|
try:
|
|
from PIL import Image, ImageTk
|
|
bild = Image.open(p).convert("RGBA").resize((groesse, groesse), Image.LANCZOS)
|
|
bild.putalpha(bild.getchannel("A").point(lambda w: int(w * deckkraft)))
|
|
fertig = ImageTk.PhotoImage(bild, master=fenster)
|
|
except Exception as e: # noqa: BLE001 - ein Wasserzeichen darf nichts blockieren
|
|
melden(f"[wasserzeichen] nicht ladbar: {e}")
|
|
return None
|
|
_lager[schluessel] = fertig
|
|
return fertig
|
|
|
|
|
|
def kopf(hoehe=28, master=None, melden=print):
|
|
"""Das Logo fuer die Kopfzeile - volle Deckkraft, kleine Hoehe.
|
|
|
|
Getrennt von hole(): dort geht es um ein blasses Wasserzeichen, hier um ein
|
|
Erkennungszeichen. Zwei Zwecke, zwei Funktionen - sonst haette eine davon
|
|
einen Schalter, den man beim Lesen nachschlagen muss.
|
|
"""
|
|
return hole(hoehe, 1.0, master=master, melden=melden)
|