Kaesten verschiebbar wie bei OPNsense: Knopf, schieben, speichern
Seine Ansage: "rechnungsdaten oben links, darunter rechnung an kunde, den tabellen kasten rechts - oder noch besser dnd einbauen" und dann genauer: "wie bei opnsense hast so einen kleinen knopf, dann drueckst drauf, ab da kannst du schieben, dann hast du einen save button, und dann ist die fest". - Seine Anordnung ist die Vorgabe (flaeche.STANDARD). - Verschieben muss man EINSCHALTEN. Ohne den Knopf sitzt alles fest, damit beim taeglichen Arbeiten nichts verrutscht. Im Modus stehen "Speichern" und "Verwerfen" daneben; erst Speichern schreibt in die config. - Waehrend des Ziehens haengt ein Etikett am Zeiger und der gegriffene Kasten wird blass - vorher sah man nur das Ziel und es wirkte "statisch" (sein Fund). - Getauscht statt frei abgelegt: freies Verschieben auf Pixel braucht Regeln fuer Ueberlappung, Groesse und leere Zellen, und am Ende steht das Fenster schief. Ein Tausch ist in einem Griff erledigt. - Der freie Platz folgt dem Kasten mit der langen Liste. Feste Gewichte gingen nicht: die Liste wandert, und der Kundenkasten wurde unten abgeschnitten. - Eine unbrauchbare Anordnung in der config faellt auf die Vorgabe zurueck. Icons: die Material Symbols vom Hub (M:/projekte/material-symbols), einmal nach PNG gewandelt und zur Laufzeit eingefaerbt (icons.py) - eine Datei je Icon, nicht drei Fassungen fuer hell/dunkel/Akzent. ⚠️ Ein PhotoImage gehoert GENAU EINEM Tk-Fenster. Der Icon-Cache reichte Bilder an das naechste weiter, sobald ein Pruefstand Journal und Rechnungstool nacheinander faehrt: 'image "pyimage1" doesn't exist'. Das Fenster wird jetzt mitgegeben, tk._default_root reicht dafuer nicht. Neu: pruef_flaeche.py. Alle 15 Pruefstaende gruen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
This commit is contained in:
parent
5403e01dd5
commit
c1e328c087
10 changed files with 561 additions and 17 deletions
62
icons.py
Normal file
62
icons.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Icons aus dem Hub-Vorrat (Material Symbols), eingefaerbt zur Laufzeit.
|
||||
|
||||
Die SVGs liegen auf dem Hub (`M:/projekte/material-symbols`) und wurden einmal
|
||||
nach PNG gewandelt - als weisse Silhouette mit Transparenz. Hier bekommen sie
|
||||
ihre Farbe: dieselbe Datei taugt fuer die Akzentfarbe, fuer gedaempfte Schrift
|
||||
und fuer das helle Thema, ohne dass jemand drei Fassungen pflegt.
|
||||
|
||||
Ohne Pillow oder ohne Datei gibt es einfach kein Bild zurueck - der Aufrufer
|
||||
zeigt dann seinen Text. Ein fehlendes Icon darf kein Fenster verhindern.
|
||||
"""
|
||||
import os
|
||||
import tkinter as tk
|
||||
|
||||
import config
|
||||
|
||||
# ⚠️ Ein PhotoImage gehoert zu GENAU EINEM Tk-Fenster. Wird ein zweites
|
||||
# aufgemacht (ein Pruefstand faehrt Journal und Rechnungstool nacheinander),
|
||||
# zeigt ein weitergereichtes Bild ins Leere: 'image "pyimage1" doesn't exist'.
|
||||
# Deshalb steht das Fenster mit im Schluessel.
|
||||
_zwischenlager = {} # (fenster, name, groesse, farbe) -> PhotoImage
|
||||
|
||||
|
||||
def _pfad(name):
|
||||
for basis in (config.BASE_DIR, config.RESOURCE_DIR,
|
||||
os.path.dirname(os.path.abspath(__file__))):
|
||||
p = os.path.join(basis, "assets", "icons", name + ".png")
|
||||
if os.path.exists(p):
|
||||
return p
|
||||
return ""
|
||||
|
||||
|
||||
def hole(name, groesse=18, farbe="#e8e8ea", master=None):
|
||||
"""Icon als PhotoImage - oder None, wenn es nicht geht.
|
||||
|
||||
`master` ist das Widget, in dem das Bild landet. Es MUSS mitgegeben werden,
|
||||
wenn mehr als ein Tk-Fenster laeuft: `tk._default_root` zeigt dann auf das
|
||||
zuerst geoeffnete, und das Bild gehoert dem falschen Fenster.
|
||||
"""
|
||||
fenster = master if master is not None else tk._default_root
|
||||
if fenster is None:
|
||||
return None
|
||||
schluessel = (id(fenster), name, groesse, farbe)
|
||||
if schluessel in _zwischenlager:
|
||||
return _zwischenlager[schluessel]
|
||||
pfad = _pfad(name)
|
||||
if not pfad:
|
||||
print(f"[icons] nicht gefunden: {name}")
|
||||
return None
|
||||
try:
|
||||
from PIL import Image, ImageTk
|
||||
bild = Image.open(pfad).convert("RGBA")
|
||||
bild = bild.resize((groesse, groesse), Image.LANCZOS)
|
||||
# Die Silhouette steckt im Alphakanal - die Farbe kommt hier drueber.
|
||||
flaeche = Image.new("RGBA", bild.size, farbe)
|
||||
flaeche.putalpha(bild.getchannel("A"))
|
||||
fertig = ImageTk.PhotoImage(flaeche, master=fenster)
|
||||
except Exception as e: # noqa: BLE001 - ein Icon darf nichts blockieren
|
||||
print(f"[icons] {name} nicht ladbar: {e}")
|
||||
return None
|
||||
_zwischenlager[schluessel] = fertig
|
||||
return fertig
|
||||
Loading…
Add table
Add a link
Reference in a new issue