Keep edit dialogs on the monitor the main window is on

_center_on_parent() hat gegen winfo_screenwidth()/screenheight() begrenzt --
Tk meldet dort aber nur den Hauptbildschirm. Lag das Hauptfenster auf einem
zweiten Monitor, zog genau diese Begrenzung den Dialog zurueck an den Rand
des ersten. Begrenzt wird jetzt gegen das Elternfenster: passt der Dialog
hinein, wird er zentriert, sonst an dessen linker oberer Ecke ausgerichtet
-- so bleibt er in jedem Fall dort, wo gearbeitet wird.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Julian Appel 2026-08-29 01:02:07 +02:00
parent 42897d553c
commit 50868ab081

View file

@ -10,10 +10,15 @@ Tastendruck-Erkennung (_KeyCapture): Tasten lassen sich statt per Dropdown
auch einfach druecken. Das laeuft ueber ganz normale Tk-Fokus-Events des auch einfach druecken. Das laeuft ueber ganz normale Tk-Fokus-Events des
Dialogfensters -- KEIN globaler WinAPI-Tastaturhook (siehe Domaenenregel Dialogfensters -- KEIN globaler WinAPI-Tastaturhook (siehe Domaenenregel
"keine Selbstversteck-/Hook-Fenstertricks"). Konsequenz: erkannt wird nur, "keine Selbstversteck-/Hook-Fenstertricks"). Konsequenz: erkannt wird nur,
was das fokussierte Fenster erreicht, und die HID-Zuordnung ist dieselbe was das fokussierte Fenster erreicht -- Win+L, Strg+Alt+Entf und aehnliche
US-Layout-Naeherung wie bei den Dropdown-Labels (siehe vom System abgefangene Kombinationen also nicht.
versapad_data.tk_event_to_hid). Das Dropdown bleibt deshalb daneben stehen,
damit ein falsch erkanntes Zeichen von Hand korrigiert werden kann. Welche physische Taste gemeint ist, loest versapad_data.tk_event_to_hid()
ueber den Scan-Code des aktiven Layouts auf (versapad_keylayout), nicht
ueber das erzeugte Zeichen -- sonst landet auf deutschem Layout jedes Y auf
der Z-Taste des Boards und AeOeUe/#/+ sind gar nicht erfassbar. Das Dropdown
daneben zeigt dieselbe Taste unter ihrem Layout-Namen und bleibt als
Korrekturmoeglichkeit stehen.
""" """
import tkinter as tk import tkinter as tk
from tkinter import colorchooser, ttk from tkinter import colorchooser, ttk
@ -192,10 +197,18 @@ class _ModalDialog(tk.Toplevel):
# ── Positionierung + Ablauf ─────────────────────────────────────── # ── Positionierung + Ablauf ───────────────────────────────────────
def _center_on_parent(self): def _center_on_parent(self):
"""Mittig ueber dem Elternfenster, aber immer vollstaendig auf dem """Mittig ueber dem Elternfenster. Ohne das oeffnet Tk jeden Toplevel
Bildschirm. Ohne das oeffnet Tk jeden Toplevel bei +0+0, also bei bei +0+0, also bei jeder bearbeiteten Taste erneut in der
jeder bearbeiteten Taste erneut in der Bildschirmecke -- weit weg Bildschirmecke -- weit weg vom Fenster, in dem gerade geklickt wurde.
vom Hauptfenster, in dem gerade geklickt wurde."""
Begrenzt wird bewusst gegen das ELTERNFENSTER, nicht gegen
`winfo_screenwidth()`: Tk meldet dort nur den Hauptbildschirm. Lag
das Hauptfenster auf einem zweiten Monitor, hat genau diese
Begrenzung den Dialog wieder auf den Rand des ersten Monitors
gezogen. Passt der Dialog nicht ins Elternfenster (der
Makro-Schritte-Dialog ist breiter als der Action-Dialog), wird er an
dessen linker oberer Ecke ausgerichtet statt zentriert -- so bleibt
er in jedem Fall auf dem Monitor, auf dem gearbeitet wird."""
parent = self.master parent = self.master
width, height = self.winfo_reqwidth(), self.winfo_reqheight() width, height = self.winfo_reqwidth(), self.winfo_reqheight()
try: try:
@ -204,10 +217,8 @@ class _ModalDialog(tk.Toplevel):
except tk.TclError: except tk.TclError:
px = py = 0 px = py = 0
pw, ph = self.winfo_screenwidth(), self.winfo_screenheight() pw, ph = self.winfo_screenwidth(), self.winfo_screenheight()
x = px + (pw - width) // 2 x = px + max(0, (pw - width) // 2)
y = py + (ph - height) // 3 # etwas oberhalb der Mitte wirkt ruhiger y = py + max(0, (ph - height) // 3) # etwas oberhalb der Mitte wirkt ruhiger
x = max(0, min(x, self.winfo_screenwidth() - width))
y = max(0, min(y, self.winfo_screenheight() - height))
self.geometry(f"+{x}+{y}") self.geometry(f"+{x}+{y}")
def run(self): def run(self):