Neu: - Eigene Kennungen (eigene Filiale) ausblenden: nicht angezeigt, nicht mitgerechnet, nicht exportiert; per Rechtsklick, Händler-Menü oder Import-Bericht; Händler-Zuordnung hat Vorrang - Menüs im Win95-Stil: wechseln beim Überfahren der Menüleiste, Tastatur, Kontextmenü gleich - Dialoge sperren nur den Inhalt: Hauptfenster bleibt verschiebbar/maximierbar; Dialoge haben eigenen Taskleisten-Eintrag; Klick auf gesperrten Inhalt holt den Dialog nach vorn (blinkt) - Trennlinie zwischen Händler- und Positionsliste sichtbar und ziehbar, Position wird gemerkt - Strg+Rücktaste / Strg+Entf löschen ganze Wörter in allen Eingabefeldern Behoben: - Gedrückte Knöpfe zeigten keine Beschriftung (activeForeground gehört in Tk zur Klasse Background) - Tipp des Tages: Text lief aus dem sichtbaren Bereich - Größenänderung: breiterer Griffbereich mit Ecken, Zeiger wird zuverlässig zurückgesetzt, flüssiger; Verschieben über Windows selbst (inkl. Andocken), Minimieren über Windows - Zeichen, die MS Sans Serif nicht hat (…, ▸, →, •), durch Win95-übliche ersetzt - Menü/Tooltip/Dialog: Größe+Position zusammen setzen (Tk ignoriert sonst die Position) - Suche reagiert erst nach kurzer Tipp-Pause (flüssigeres Tippen) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
94 lines
3.2 KiB
Python
94 lines
3.2 KiB
Python
"""Modale Sperre ohne Tk-„grab“: Nur der INHALT des aufrufenden Fensters wird gesperrt.
|
||
|
||
Titelleiste und Rand bleiben bedienbar – das Hauptfenster lässt sich also verschieben, maximieren
|
||
und in der Größe ändern, während ein Dialog offen ist. Klickt man auf den gesperrten Inhalt, kommt
|
||
der Dialog nach vorn und blinkt kurz (wie bei Windows).
|
||
|
||
Technik: Jedes Widget im gesperrten Bereich bekommt vorn das Bindungs-Tag ``Pm95Gesperrt``. Dessen
|
||
Bindungen laufen vor allen anderen und beenden Klicks/Tastendrücke mit „break“.
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import tkinter as tk
|
||
|
||
TAG = "Pm95Gesperrt"
|
||
_stapel: list[tk.Toplevel] = [] # offene modale Fenster, innerstes zuletzt
|
||
|
||
GESPERRTE_EREIGNISSE = ("<ButtonPress>", "<ButtonRelease>", "<Double-ButtonPress>", "<Triple-ButtonPress>",
|
||
"<B1-Motion>", "<KeyPress>", "<KeyRelease>", "<MouseWheel>")
|
||
|
||
|
||
def oberstes() -> tk.Toplevel | None:
|
||
"""Das zuletzt geöffnete, noch offene modale Fenster (oder None)."""
|
||
while _stapel:
|
||
d = _stapel[-1]
|
||
try:
|
||
if d.winfo_exists():
|
||
return d
|
||
except tk.TclError:
|
||
pass
|
||
_stapel.pop()
|
||
return None
|
||
|
||
|
||
def offen() -> bool:
|
||
return oberstes() is not None
|
||
|
||
|
||
def _gesperrt_geklickt(event):
|
||
d = oberstes()
|
||
if d is not None and hasattr(d, "nach_vorn"):
|
||
d.nach_vorn(blinken=str(event.type) in ("ButtonPress", "4"))
|
||
return "break"
|
||
|
||
|
||
def _einrichten(root: tk.Misc):
|
||
# Merker am Tk-Objekt selbst (nicht am Namen: das Hauptfenster heißt in jeder Tk-Instanz „.“)
|
||
if getattr(root, "_pm95_sperre_eingerichtet", False):
|
||
return
|
||
for seq in GESPERRTE_EREIGNISSE:
|
||
root.bind_class(TAG, seq, _gesperrt_geklickt)
|
||
root._pm95_sperre_eingerichtet = True
|
||
|
||
|
||
def sperrbereiche(fenster: tk.Misc) -> list[tk.Misc]:
|
||
"""Welche Widgets eines Fensters gesperrt werden: alles außer Titelleiste (und Rand)."""
|
||
eigene = getattr(fenster, "sperrbereich", None)
|
||
if callable(eigene):
|
||
return list(eigene())
|
||
titel = getattr(fenster, "titelleiste", None)
|
||
return [k for k in fenster.winfo_children() if k is not titel and not isinstance(k, tk.Toplevel)]
|
||
|
||
|
||
class Sperre:
|
||
"""Sperrt den Inhalt von `fenster`, solange `dialog` offen ist."""
|
||
|
||
def __init__(self, fenster: tk.Misc, dialog: tk.Toplevel):
|
||
_einrichten(fenster._root())
|
||
self.widgets: list[tk.Misc] = []
|
||
for bereich in sperrbereiche(fenster):
|
||
self._sperren(bereich)
|
||
_stapel.append(dialog)
|
||
self.dialog = dialog
|
||
|
||
def _sperren(self, w: tk.Misc):
|
||
if isinstance(w, tk.Toplevel):
|
||
return # eigene Fenster (z. B. andere Dialoge) nicht anfassen
|
||
tags = w.bindtags()
|
||
if TAG not in tags:
|
||
w.bindtags((TAG,) + tuple(tags))
|
||
self.widgets.append(w)
|
||
for kind in w.winfo_children():
|
||
self._sperren(kind)
|
||
|
||
def aufheben(self):
|
||
for w in self.widgets:
|
||
try:
|
||
if w.winfo_exists():
|
||
w.bindtags(tuple(t for t in w.bindtags() if t != TAG))
|
||
except tk.TclError:
|
||
pass
|
||
self.widgets = []
|
||
if self.dialog in _stapel:
|
||
_stapel.remove(self.dialog)
|