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:
parent
f57c7f52f4
commit
755c844ee4
6 changed files with 104 additions and 12 deletions
2
app.py
2
app.py
|
|
@ -271,7 +271,7 @@ class App(theme.ThemeMixin, tk.Tk):
|
|||
ttk.Separator(rahmen, orient="horizontal").pack(fill="x", pady=(12, 10))
|
||||
ttk.Button(rahmen, text="Schließen", width=14,
|
||||
command=d.destroy).pack(anchor="e")
|
||||
d.geometry(f"+{self.winfo_rootx() + 120}+{self.winfo_rooty() + 140}")
|
||||
theme.mittig(d, self)
|
||||
return d
|
||||
|
||||
def _fenstersymbol(self):
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ hinueber.
|
|||
"""
|
||||
|
||||
import os
|
||||
import theme
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, filedialog, messagebox
|
||||
|
||||
|
|
@ -91,7 +92,8 @@ class OrdnerWahl(tk.Toplevel):
|
|||
hoehe = max(self.winfo_reqheight(), 300)
|
||||
x = master.winfo_rootx() + max(0, (master.winfo_width() - BREITE) // 2)
|
||||
y = master.winfo_rooty() + 90
|
||||
self.geometry(f"{BREITE}x{hoehe}+{max(0, x)}+{max(0, y)}")
|
||||
self.geometry(f"{BREITE}x{hoehe}")
|
||||
theme.mittig(self, master)
|
||||
self.minsize(BREITE, hoehe)
|
||||
self.grab_set()
|
||||
self.lift()
|
||||
|
|
|
|||
|
|
@ -156,6 +156,28 @@ for wunsch, soll_dunkel in (("hell", False), ("dunkel", True)):
|
|||
f"in '{wunsch}' ist keine Farbe der anderen Darstellung "
|
||||
f"uebrig ({reste[:3]})")
|
||||
|
||||
# ---- Dialoge gehen mittig ueber dem Programmfenster auf ------------------
|
||||
# Seine Ansage: "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. Vorher klemmte ein max(0, x) jede negative Koordinate auf
|
||||
# null und riss die Fenster auf den Hauptmonitor zurueck.
|
||||
d = f.dlg_darstellung()
|
||||
pumpen(1.2)
|
||||
d.update_idletasks()
|
||||
mitte_dialog = d.winfo_rootx() + d.winfo_width() // 2
|
||||
mitte_fenster = f.winfo_rootx() + f.winfo_width() // 2
|
||||
pruefe(abs(mitte_dialog - mitte_fenster) <= 30,
|
||||
f"der Dialog steht mittig ueber dem Fenster "
|
||||
f"({mitte_dialog} vs. {mitte_fenster})")
|
||||
pruefe(d.winfo_rootx() >= f.winfo_rootx() - 40
|
||||
and d.winfo_rootx() + d.winfo_width() <= f.winfo_rootx() + f.winfo_width() + 40,
|
||||
"und liegt waagerecht innerhalb des Fensters")
|
||||
pruefe(d.winfo_rooty() >= f.winfo_rooty() - 40,
|
||||
"und nicht oberhalb davon")
|
||||
d.destroy()
|
||||
pumpen(0.3)
|
||||
|
||||
# ---- Zurueck auf automatisch --------------------------------------------
|
||||
f.cfg["darstellung"] = "auto"
|
||||
f._oberflaeche_neu()
|
||||
|
|
|
|||
|
|
@ -64,7 +64,15 @@ if dieses is None:
|
|||
print("ROT | ohne Release ist der Rest nicht pruefbar")
|
||||
sys.exit(1)
|
||||
|
||||
anhaenge = {a.get("name"): a for a in dieses.get("assets") or []}
|
||||
roh = dieses.get("assets") or []
|
||||
anhaenge = {a.get("name"): a for a in roh}
|
||||
# Doppelte Namen: Forgejo laesst zwei Anhaenge mit demselben Namen zu. Beim
|
||||
# Ersetzen einer Datei blieb die alte einmal stehen (07.09.2026), und welche
|
||||
# von beiden der Updater dann laedt, ist Glueckssache - unter Umstaenden die
|
||||
# alte, mit der falschen Pruefsumme daneben.
|
||||
doppelt = sorted({a["name"] for a in roh
|
||||
if sum(1 for b in roh if b["name"] == a["name"]) > 1})
|
||||
pruefe(not doppelt, f"kein Anhang haengt doppelt am Release ({doppelt})")
|
||||
print(f" (Anhaenge: {', '.join(sorted(anhaenge)) or 'keine'})")
|
||||
|
||||
pruefe(version.EXE_NAME in anhaenge,
|
||||
|
|
|
|||
|
|
@ -57,7 +57,12 @@ if not os.path.exists(EXE):
|
|||
sys.exit(0)
|
||||
|
||||
u = ctypes.windll.user32
|
||||
p = subprocess.Popen([EXE])
|
||||
# Mit --test: dann geht das Fenster auf dem ZWEITEN Monitor auf und nicht
|
||||
# mitten auf dem Hauptbildschirm, wo gerade jemand arbeitet. Seine Ansage am
|
||||
# 07.09.2026 - und dieser Pruefstand war der eine, der sie noch nicht befolgte,
|
||||
# weil er die gebaute EXE ganz normal startet. Sichtbar bleibt das Fenster,
|
||||
# und genau das wird hier ja geprueft.
|
||||
p = subprocess.Popen([EXE, "--test"])
|
||||
print(f" (gestartet: {os.path.basename(EXE)}, PID {p.pid})")
|
||||
|
||||
RUECKRUF = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM)
|
||||
|
|
|
|||
71
theme.py
71
theme.py
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue