Fix right-click context menus firing their first item on Linux

Bound to <Button-3> with finally: menu.grab_release(), the menu lost its grab
immediately and the trailing <ButtonRelease-3> activated the entry under the
cursor — right-clicking a history row jumped straight into the edit dialog and
deleting was impossible.

- RIGHT_CLICK constant: <ButtonRelease-3> (<ButtonRelease-2> on macOS)
- history + queue menus built once on self, not per click
- drop the premature grab_release()

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-07 22:41:10 +02:00
parent 5eb60ec2d3
commit 0b6ed854dc
4 changed files with 55 additions and 20 deletions
+31 -19
View File
@@ -54,6 +54,10 @@ UI_FONT_SIZE = 11
#: DRK-Rot für Akzente in der Oberfläche und die Kartenpunkte.
DRK_RED = "#CC0000"
#: Rechtsklick-Event. ``<ButtonRelease-…>`` statt ``<Button-…>``: sonst landet
#: unter X11 das Loslassen der Maustaste direkt im ersten Menüeintrag.
RIGHT_CLICK = "<ButtonRelease-2>" if sys.platform == "darwin" else "<ButtonRelease-3>"
#: Regionen, die bei der Geokodierung bevorzugt durchsucht werden (Reihenfolge zählt).
GEOCODE_REGIONS = ["Baden-Württemberg", "Hessen"]
@@ -1050,8 +1054,16 @@ class App(ttk.Window):
self.tree.pack(side=LEFT, fill=BOTH, expand=True)
sb.pack(side=RIGHT, fill=Y)
self._queue_menu = tk.Menu(self, tearoff=0)
self._queue_menu.add_command(
label="Entfernen", command=self._delete_selected_queue_rows
)
self._queue_menu.add_command(
label="Koordinaten erneut suchen", command=self._retry_selected_geocode
)
self.tree.bind("<ButtonRelease-1>", self._on_tree_click)
self.tree.bind("<Button-3>", self._on_queue_right_click)
self.tree.bind(RIGHT_CLICK, self._on_queue_right_click)
self.tree.bind("<Delete>", lambda _e: self._delete_selected_queue_rows())
# Aktionsleiste
@@ -1113,8 +1125,16 @@ class App(ttk.Window):
self.hist_tree.tag_configure("missing", foreground=DRK_RED)
self._hist_menu = tk.Menu(self, tearoff=0)
self._hist_menu.add_command(label="Bearbeiten…", command=self._on_hist_edit)
self._hist_menu.add_command(
label="Koordinaten suchen", command=self._on_hist_geocode
)
self._hist_menu.add_separator()
self._hist_menu.add_command(label="Löschen", command=self._on_hist_delete)
self.hist_tree.bind("<Double-1>", self._on_hist_double_click)
self.hist_tree.bind("<Button-3>", self._on_hist_right_click)
self.hist_tree.bind(RIGHT_CLICK, self._on_hist_right_click)
self._sort_col = "date"
self._sort_asc = False # neueste zuerst
@@ -1212,15 +1232,8 @@ class App(ttk.Window):
if not iid:
return
self.hist_tree.selection_set(iid)
menu = tk.Menu(self, tearoff=0)
menu.add_command(label="Bearbeiten", command=self._on_hist_edit)
menu.add_command(label="Koordinaten suchen", command=self._on_hist_geocode)
menu.add_separator()
menu.add_command(label="Löschen", command=self._on_hist_delete)
try:
menu.tk_popup(event.x_root, event.y_root)
finally:
menu.grab_release()
self.hist_tree.focus(iid)
self._hist_menu.tk_popup(event.x_root, event.y_root)
def _on_hist_geocode(self) -> None:
sel = self.hist_tree.selection()
@@ -1406,14 +1419,13 @@ class App(ttk.Window):
row_id = self.tree.identify_row(event.y)
if not row_id:
return
menu = tk.Menu(self, tearoff=0)
menu.add_command(label="Löschen", command=lambda: self._delete_queue_row(row_id))
menu.add_command(label="Koordinaten erneut suchen",
command=lambda: self._retry_geocode(row_id))
try:
menu.tk_popup(event.x_root, event.y_root)
finally:
menu.grab_release()
if row_id not in self.tree.selection():
self.tree.selection_set(row_id)
self._queue_menu.tk_popup(event.x_root, event.y_root)
def _retry_selected_geocode(self) -> None:
for row_id in self.tree.selection():
self._retry_geocode(row_id)
def _delete_queue_row(self, row_id: str) -> None:
self._queue = [r for r in self._queue if r["_id"] != row_id]