Popups gehen mittig ueber dem Programmfenster auf

Gleiche Aenderung wie im Rechnungstool, gleiche theme.py: theme.mittig()
setzt jeden Dialog mittig ueber sein Elternfenster, theme.auf_bildschirm()
begrenzt auf den gesamten Desktop ueber alle Monitore statt auf den
Hauptmonitor.

Sein Befund: "da gehen noch die popups auf dem video monitor auf". Ursache
war ein `max(0, x)`, das jede negative Koordinate auf null klemmte - bei ihm
steht der zweite Monitor links (x = -1920).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V4t48uxDok5rJXhC9bX1Ax
This commit is contained in:
TheMockTv 2026-09-07 00:53:00 +02:00
parent f57c7f52f4
commit 755c844ee4
6 changed files with 104 additions and 12 deletions

View file

@ -121,6 +121,63 @@ def pruefplatz():
return ""
def auf_bildschirm(x, y, breite=0, hoehe=0):
"""Eine Fensterposition auf den sichtbaren Bereich begrenzen.
Frueher stand an diesen Stellen `max(0, x)`. Das sollte verhindern, dass
ein Dialog ausserhalb des Bildschirms aufgeht - klemmt aber jede NEGATIVE
Koordinate auf null. Steht der zweite Monitor links (bei ihm x = -1920),
sprang damit jedes Popup zurueck auf den Hauptbildschirm, obwohl das
Programm nebenan lief. Sein Befund am 07.09.2026: *"da gehen noch die
popups auf dem video monitor auf"*.
Begrenzt wird deshalb auf den GESAMTEN Desktop ueber alle Monitore
(SM_*VIRTUALSCREEN), nicht auf den Hauptmonitor.
"""
if not sys.platform.startswith("win"):
return int(x), int(y)
try:
import ctypes
hole = ctypes.windll.user32.GetSystemMetrics
links, oben = hole(76), hole(77)
rechts, unten = links + hole(78), oben + hole(79)
if breite:
x = min(x, rechts - breite)
if hoehe:
y = min(y, unten - hoehe)
return int(max(links, x)), int(max(oben, y))
except Exception: # noqa: BLE001 - dann eben ungebremst
return int(x), int(y)
def mittig(dialog, ueber):
"""Einen Dialog mittig ueber sein Elternfenster setzen.
Seine Ansage am 07.09.2026: *"einfach so programmieren das die popup auf
dem fenster mittig vom main fenster auf gehen"*.
Das ist zugleich die Antwort auf die Monitorfrage: steht das Programm auf
dem zweiten Bildschirm, geht der Dialog dort auf - ohne dass irgendwo ein
Monitor gesucht werden muesste. Vorher standen an den Dialogen feste
Versaetze ("+120+140") und ein `max(0, x)`, das jede negative Koordinate
auf null klemmte und die Fenster damit auf den Hauptmonitor zurueckriss.
Etwas oberhalb der Mitte (ein Drittel statt der Haelfte): so sitzt der
Dialog dort, wo der Blick ohnehin ist, und verdeckt nicht die Mitte des
Formulars darunter.
"""
try:
dialog.update_idletasks()
breite = dialog.winfo_reqwidth() or dialog.winfo_width()
hoehe = dialog.winfo_reqheight() or dialog.winfo_height()
x = ueber.winfo_rootx() + (ueber.winfo_width() - breite) // 2
y = ueber.winfo_rooty() + (ueber.winfo_height() - hoehe) // 3
x, y = auf_bildschirm(x, y, breite, hoehe)
dialog.geometry(f"+{x}+{y}")
except tk.TclError:
pass # Fenster schon zu - dann ist die Position gleichgueltig
def testlauf():
"""Faehrt gerade ein Pruefstand das Programm?
@ -532,11 +589,12 @@ class ThemeMixin:
und Tastatur fest, waehrend nebenan jemand schreibt.
"""
d.configure(bg=self.col_bg)
# Mittig ueber dem Programmfenster - und damit automatisch auf dem
# Bildschirm, auf dem das Programm gerade steht.
d.after(1, lambda: mittig(d, self))
if testlauf():
# Wie das Hauptfenster: auf den zweiten Monitor, und ohne grab_set -
# ein Dialog, der Maus und Tastatur festhaelt, blockiert den
# Menschen, der nebenher arbeitet.
d.geometry(pruefplatz() or f"+{d.winfo_screenwidth() + 20}+40")
# Ohne grab_set: ein Dialog, der Maus und Tastatur festhaelt,
# blockiert den Menschen, der nebenher arbeitet.
d.grab_set = lambda *a, **k: None
try:
d.attributes("-toolwindow", True) # nicht in die Taskleiste
@ -639,10 +697,7 @@ class MeldungMixin:
d.bind("<Escape>", lambda _e: schliessen(False))
d.protocol("WM_DELETE_WINDOW", lambda: schliessen(False))
d.update_idletasks()
x = self.winfo_rootx() + max(0, (self.winfo_width() - d.winfo_reqwidth()) // 2)
y = self.winfo_rooty() + 140
d.geometry(f"+{max(0, x)}+{max(0, y)}")
mittig(d, self)
# Nach vorn holen und den Tastaturfokus nehmen. Ohne das kann der Dialog
# beim Start hinter dem Hauptfenster liegen - der Nutzer sieht nur ein
# Fenster, das nicht reagiert, und haelt es fuer haengen geblieben.