Skip to content

Commit 1364b8d

Browse files
committed
feat: add cell tooltip functionality to batch and watchlist tables
1 parent e6e7474 commit 1364b8d

3 files changed

Lines changed: 106 additions & 0 deletions

File tree

convertible_bond/gui/tabs/batch.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from .batch_common import (
3333
_TREE_ATTRS,
3434
_apply_tag_colors,
35+
_attach_cell_tooltip,
3536
_attach_column_sort,
3637
_configure_responsive_columns,
3738
_configure_tree_style,
@@ -531,6 +532,7 @@ def _render_table(app, results, *, total_results=None, view=None, cache_path=Non
531532

532533
_apply_tag_colors(tree)
533534
_attach_column_sort(tree, columns, headers)
535+
_attach_cell_tooltip(tree, columns, headers, tooltip_headers={"标签", "复核建议"})
534536
app._batch_main_tree = tree
535537
_TREE_ATTRS.add("_batch_main_tree")
536538
_attach_main_context_menu(app, tree)

convertible_bond/gui/tabs/batch_common.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from __future__ import annotations
77

88
import math
9+
import tkinter as tk
910
from datetime import date, datetime
1011
from tkinter import ttk
1112

@@ -336,3 +337,104 @@ def on_click(idx: int) -> None:
336337

337338
for i, col in enumerate(columns):
338339
tree.heading(col, command=lambda i=i: on_click(i))
340+
341+
342+
def _attach_cell_tooltip(
343+
tree: ttk.Treeview,
344+
columns,
345+
headers,
346+
*,
347+
tooltip_headers: set[str] | None = None,
348+
delay_ms: int = 300,
349+
) -> None:
350+
"""给 Treeview 指定列加悬浮完整文本提示.
351+
352+
主要用于"标签"、"复核建议"这类长文本列。tooltip 内容直接取当前单元格
353+
display value, 因此表头排序后也能自然跟随行移动。
354+
"""
355+
targets = set(tooltip_headers or headers)
356+
state = {"tip": None, "after": None, "cell": None}
357+
358+
def _cancel_after() -> None:
359+
after_id = state.get("after")
360+
if after_id is not None:
361+
try:
362+
tree.after_cancel(after_id)
363+
except Exception:
364+
pass
365+
state["after"] = None
366+
367+
def _hide(_event=None) -> None:
368+
_cancel_after()
369+
tip = state.get("tip")
370+
if tip is not None:
371+
try:
372+
tip.destroy()
373+
except Exception:
374+
pass
375+
state["tip"] = None
376+
state["cell"] = None
377+
378+
def _show(text: str, x_root: int, y_root: int) -> None:
379+
tip = tk.Toplevel(tree)
380+
tip.wm_overrideredirect(True)
381+
try:
382+
tip.attributes("-topmost", True)
383+
except tk.TclError:
384+
pass
385+
label = tk.Label(
386+
tip,
387+
text=text,
388+
justify="left",
389+
wraplength=460,
390+
background=get_color(BG_INPUT),
391+
foreground=get_color(TEXT),
392+
relief="solid",
393+
borderwidth=1,
394+
padx=8,
395+
pady=6,
396+
font=(FONT_FAMILY, 12),
397+
)
398+
label.pack()
399+
tip.wm_geometry(f"+{x_root + 12}+{y_root + 16}")
400+
state["tip"] = tip
401+
402+
def _motion(event) -> None:
403+
row_id = tree.identify_row(event.y)
404+
col_id = tree.identify_column(event.x)
405+
if not row_id or not col_id:
406+
_hide()
407+
return
408+
try:
409+
col_idx = int(col_id.lstrip("#")) - 1
410+
except ValueError:
411+
_hide()
412+
return
413+
if col_idx < 0 or col_idx >= len(columns):
414+
_hide()
415+
return
416+
header = headers[col_idx]
417+
if header not in targets:
418+
_hide()
419+
return
420+
value = str(tree.set(row_id, columns[col_idx]) or "").strip()
421+
if not value or value in {"—", "-"}:
422+
_hide()
423+
return
424+
cell = (row_id, col_idx, value)
425+
if state.get("cell") == cell:
426+
tip = state.get("tip")
427+
if tip is not None:
428+
tip.wm_geometry(f"+{event.x_root + 12}+{event.y_root + 16}")
429+
return
430+
_hide()
431+
state["cell"] = cell
432+
state["after"] = tree.after(
433+
delay_ms,
434+
lambda text=value, x=event.x_root, y=event.y_root: _show(text, x, y),
435+
)
436+
437+
tree.bind("<Motion>", _motion, add="+")
438+
tree.bind("<Leave>", _hide, add="+")
439+
tree.bind("<ButtonPress>", _hide, add="+")
440+
tree.bind("<MouseWheel>", _hide, add="+")

convertible_bond/gui/tabs/batch_watchlist.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from .batch_common import (
3131
_TREE_ATTRS,
3232
_apply_tag_colors,
33+
_attach_cell_tooltip,
3334
_attach_column_sort,
3435
_configure_responsive_columns,
3536
_configure_tree_style,
@@ -343,6 +344,7 @@ def _render_watchlist_table(app):
343344

344345
_apply_tag_colors(tree)
345346
_attach_column_sort(tree, columns, headers)
347+
_attach_cell_tooltip(tree, columns, headers, tooltip_headers={"标签"})
346348

347349
if not rows:
348350
placeholder = ctk.CTkLabel(

0 commit comments

Comments
 (0)