You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取ttk.Notebook创建的实际标签页部件?

给ttk.Notebook标签页添加自定义Tooltip的实现方案

问题描述

需要给ttk.Notebook顶部的实际标签页部件(即点击切换的标签部分)添加自定义Tooltip,而非绑定到标签页对应的内容Frame。如果绑定到内容Frame,Tooltip会出现在Notebook的内容区域,遮挡视图。

已知Notebook的children属性返回空字典,tabs()方法仅能返回内容Frame的tab_id字符串元组,无法直接获取标签页部件。

自定义Tooltip类代码

import tkinter as tk
from tkinter import ttk

class ToolTip:
    X_OFFSET = 20
    Y_OFFSET = 20
    JUSTIFY = tk.LEFT
    BG_COLOR = "#ffffe0"  # 浅黄色
    RELIEF = tk.SOLID
    BORDER_WIDTH = 1

    @property
    def text(self) -> str:
        return self.__text

    @text.setter
    def text(self, value: str) -> None:
        self.__text = value

    @property
    def x(self) -> int:
        return self._widget.winfo_rootx() + self._x

    @property
    def y(self) -> int:
        return self._widget.winfo_rooty() + self._y

    def __init__(self, widget: tk.Widget, text: str) -> None:
        self._widget = widget
        self.text = text
        self._tip_window = None
        self._tip_showing_id = None
        self._x = self._y = 0
        self._bind_callbacks()

    def _bind_callbacks(self) -> None:
        self._entering_id = self._widget.bind("<Enter>", self._on_entered)
        self._leaving_id = self._widget.bind("<Leave>", self._on_left)
        self._button_pressing_id = self._widget.bind("<ButtonPress>", self._on_left)

    def _unbind_callbacks(self) -> None:
        self._widget.unbind("<Enter>", self._entering_id)
        self._widget.unbind("<Leave>", self._leaving_id)
        self._widget.unbind("<ButtonPress>", self._button_pressing_id)

    def _on_entered(self, event: tk.Event) -> None:
        self._x, self._y = event.x, event.y
        self._schedule()

    def _on_left(self, _) -> None:
        self._unschedule()
        self._hide_tip()

    def _schedule(self) -> None:
        self._unschedule()
        self._tip_showing_id = self._widget.after(1500, self._show_tip)

    def _unschedule(self) -> None:
        widget_id = self._tip_showing_id
        self._tip_showing_id = None
        if widget_id:
            self._widget.after_cancel(widget_id)

    def _show_tip(self) -> None:
        if self._tip_window or not self.text:
            return
        self._tip_window = tw = tk.Toplevel(self._widget)
        tw.wm_overrideredirect(True)
        tw.wm_geometry('+%d+%d' % (self.x, self.y))
        label = tk.Label(
            self._tip_window,
            text=self.text,
            justify=self.JUSTIFY,
            background=self.BG_COLOR,
            relief=self.RELIEF,
            borderwidth=self.BORDER_WIDTH
        )
        label.pack(ipadx=5, ipady=2)

    def _hide_tip(self) -> None:
        tw = self._tip_window
        self._tip_window = None
        if tw:
            tw.destroy()

解决方案

无需单独获取标签页部件,通过以下两步即可实现需求:

  1. 绑定Tooltip到Notebook实例:将ttk.Notebook对象直接传入Tooltip,而非内容Frame。此时Tooltip会显示在标签页上方区域,不会遮挡内容。
  2. 动态切换Tooltip文本:给Notebook绑定<<Motion>>事件,在回调中根据鼠标悬浮的标签,修改Tooltip的text属性。示例代码如下:
def update_tooltip_text(event):
    notebook = event.widget
    index = notebook.index(notebook.identify(event.x, event.y))
    if index != -1:
        # 可根据实际需求自定义每个标签的提示文本
        tip_text = [f"标签{index+1}的详细说明", "第二个标签的提示内容", "第三个标签的补充信息"][index]
        tooltip.text = tip_text
    else:
        tooltip.text = ""

# 创建Notebook和标签页
root = tk.Tk()
notebook = ttk.Notebook(root)
frame1 = ttk.Frame(notebook)
frame2 = ttk.Frame(notebook)
frame3 = ttk.Frame(notebook)
notebook.add(frame1, text="标签1")
notebook.add(frame2, text="标签2")
notebook.add(frame3, text="标签3")
notebook.pack(padx=10, pady=10)

# 创建Tooltip并绑定事件
tooltip = ToolTip(notebook, "")
notebook.bind("<<Motion>>", update_tooltip_text)

root.mainloop()

总结

  • 核心思路:直接将Tooltip绑定到ttk.Notebook对象,而非内容Frame
  • 通过<<Motion>>事件监听鼠标位置,动态更新Tooltip文本,实现每个标签对应不同提示的效果

内容的提问来源于stack exchange,提问作者z33k

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:10:59