Pruefstaende auf den zweiten Monitor, Desktop-Verknuepfung mit Symbol

Seine Ansage: "teste links auf dem 1080p monitor nicht mehr auf dem main ...
weil da schau ich nun video" - und danach "das nun der richtige das fuer
beide".

Dieses Programm hatte ueberhaupt keine Sonderposition fuer den Testlauf:
seine Pruefstandsfenster gingen mitten auf den Hauptbildschirm auf, waehrend
jemand daran arbeitete. Jetzt auf dem zweiten Monitor und ohne Eintrag in der
Taskleiste, wie im Rechnungstool.

Der Platz kommt aus theme.pruefplatz() - dieselbe Datei in beiden Programmen.

Dazu im Installer: der Haken "Verknuepfung auf dem Desktop" ist vorgesetzt
statt abgewaehlt, und jede Verknuepfung traegt IconFilename ausdruecklich.

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:41:36 +02:00
parent 9d7aa1eec7
commit f57c7f52f4
3 changed files with 82 additions and 6 deletions

View file

@ -66,8 +66,11 @@ AppComments=Erprobungsfassung. Benutzung auf eigene Gefahr.
Name: "deutsch"; MessagesFile: "compiler:Languages\German.isl"
[Tasks]
; Kein "unchecked": der Haken ist vorgesetzt. Er hatte nach dem
; Installieren kein Symbol auf dem Desktop und musste das Programm
; suchen (07.09.2026). Wer es nicht will, nimmt den Haken heraus.
Name: "desktopicon"; Description: "Verknüpfung auf dem Desktop anlegen"; \
GroupDescription: "Zusätzliche Verknüpfungen:"; Flags: unchecked
GroupDescription: "Zusätzliche Verknüpfungen:"
[Files]
; Der Updater - das ist, was der Benutzer startet.
@ -78,9 +81,11 @@ Source: "dist\{#ExeProgramm}"; DestDir: "{app}"; Flags: ignoreversion
[Icons]
; Beide Verknuepfungen zeigen auf den UPDATER, nicht auf das Programm.
Name: "{group}\{#Name}"; Filename: "{app}\{#ExeUpdater}"
; IconFilename ausdruecklich: ohne das erbt die Verknuepfung das Symbol vom
; UPDATER, und Windows zeigte an ihrer Stelle das nackte Standardsymbol.
Name: "{group}\{#Name}"; Filename: "{app}\{#ExeUpdater}"; IconFilename: "{app}\{#ExeProgramm}"
Name: "{group}\{#Name} deinstallieren"; Filename: "{uninstallexe}"
Name: "{userdesktop}\{#Name}"; Filename: "{app}\{#ExeUpdater}"; Tasks: desktopicon
Name: "{userdesktop}\{#Name}"; Filename: "{app}\{#ExeUpdater}"; IconFilename: "{app}\{#ExeProgramm}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#ExeUpdater}"; Description: "{#Name} jetzt starten"; \

16
app.py
View file

@ -86,6 +86,22 @@ class App(theme.ThemeMixin, tk.Tk):
self._fenstersymbol()
self.geometry("1000x680")
self.minsize(820, 520)
if TESTLAUF:
# Ein Pruefstand bedient das Programm, waehrend nebenan jemand
# arbeitet. Das Fenster geht deshalb auf dem ZWEITEN Monitor auf -
# sichtbar, aber nicht im Weg. Seine Ansage am 07.09.2026: "teste
# links auf dem 1080p monitor nicht mehr auf dem main". Bisher
# ging es hier mitten auf den Hauptbildschirm.
platz = theme.pruefplatz()
if platz:
self.geometry(platz)
try:
# Kein Eintrag in der Taskleiste: ein Eintrag, den man
# anklickt, ohne dass etwas erscheint, ist schlimmer als
# gar keiner.
self.attributes("-toolwindow", True)
except tk.TclError:
pass
self.journal = db.Journal(JOURNAL)
# Die Einstellungen des Programms liegen in der Journal-Tabelle, nicht

View file

@ -66,6 +66,61 @@ def titelleiste_faerben(fenster, dunkel):
return False
def pruefplatz():
"""Wo ein Pruefstand seine Fenster aufmachen soll: "+x+y" oder "".
Seine Ansage am 07.09.2026: *"teste links auf dem 1080p monitor nicht mehr
auf dem main ... weil da schau ich nun video"*.
Vorher lag der Platz bei `Bildschirmbreite + 20` - also RECHTS neben dem
Hauptmonitor. Bei ihm steht der zweite Monitor aber LINKS (x = -1920), und
rechts ist gar nichts: die Fenster gingen ins Leere. Sie liefen zwar, waren
aber nirgends zu sehen - das hat beim Bildermachen einige Zeit gekostet.
Gesucht wird deshalb der nicht-primaere Monitor. Gibt es keinen, bleibt es
beim alten Verhalten (neben den Bildschirm), denn im Weg sein soll ein
Pruefstand auch dann nicht.
"""
if not sys.platform.startswith("win"):
return ""
try:
import ctypes
from ctypes import wintypes
class RECT(ctypes.Structure):
_fields_ = [("left", ctypes.c_long), ("top", ctypes.c_long),
("right", ctypes.c_long), ("bottom", ctypes.c_long)]
class MONITORINFO(ctypes.Structure):
_fields_ = [("cbSize", wintypes.DWORD), ("rcMonitor", RECT),
("rcWork", RECT), ("dwFlags", wintypes.DWORD)]
gefunden = []
def je_monitor(hmon, hdc, lprect, daten):
info = MONITORINFO()
info.cbSize = ctypes.sizeof(MONITORINFO)
if ctypes.windll.user32.GetMonitorInfoW(hmon, ctypes.byref(info)):
r = info.rcWork
gefunden.append((bool(info.dwFlags & 1), # 1 = MONITORINFOF_PRIMARY
r.left, r.top, r.right - r.left))
return 1
RUECKRUF = ctypes.WINFUNCTYPE(ctypes.c_int, wintypes.HMONITOR,
wintypes.HDC, ctypes.POINTER(RECT),
wintypes.LPARAM)
ctypes.windll.user32.EnumDisplayMonitors(0, 0, RUECKRUF(je_monitor), 0)
# Der breiteste Nebenmonitor - bei mehreren der linkeste.
neben = sorted((m for m in gefunden if not m[0]),
key=lambda m: (-m[3], m[1]))
if neben:
_, x, y, _ = neben[0]
return f"+{x + 30}+{y + 40}"
except Exception: # noqa: BLE001 - dann eben der alte Weg
pass
return ""
def testlauf():
"""Faehrt gerade ein Pruefstand das Programm?
@ -478,10 +533,10 @@ class ThemeMixin:
"""
d.configure(bg=self.col_bg)
if testlauf():
# Wie das Hauptfenster: neben den Bildschirm, und ohne grab_set -
# Wie das Hauptfenster: auf den zweiten Monitor, und ohne grab_set -
# ein Dialog, der Maus und Tastatur festhaelt, blockiert den
# Menschen, der nebenher schreibt.
d.geometry(f"+{d.winfo_screenwidth() + 20}+40")
# Menschen, der nebenher arbeitet.
d.geometry(pruefplatz() or f"+{d.winfo_screenwidth() + 20}+40")
d.grab_set = lambda *a, **k: None
try:
d.attributes("-toolwindow", True) # nicht in die Taskleiste