【tkinter】ラベルにマウスオーバーでツールチップを表示する

tkinterを使って、テキストにマウスオーバーで表示されるツールチップを作成します。

下記画像のようなイメージです。

環境

python : 3.12.3
tkinter:8.6

コード

import tkinter as tk


class ToolTip:
    def __init__(self, widget: tk.Label, text: str):
        self.widget = widget
        self.text = text
        self.tip_window = None
        # マウスオーバーメソッドをバインド
        self.widget.bind("<Enter>", self.show_tip)
        # マウスリーブメソッドをバインド
        self.widget.bind("<Leave>", self.hide_tip)

    def show_tip(self, event=None):
        """ツールチップ表示"""

        # ツールチップが既に存在する or 表示文字列が設定されていない場合、表示処理をしない
        if self.tip_window or not self.text:
            return

        # ツールチップを表示する位置を取得
        x = self.widget.winfo_rootx() + 20
        y = self.widget.winfo_rooty() + 20
        # ツールチップウィンドウを作成
        self.tip_window = tk.Toplevel(self.widget)
        # ツールチップウィンドウの枠を削除
        self.tip_window.wm_overrideredirect(True)
        # ツールチップウィンドウの表示位置を設定
        self.tip_window.wm_geometry(f"+{x}+{y}")
        label = tk.Label(
            self.tip_window,
            text=self.text,
            justify="left",
            background="#ffffe0",
            relief="solid",
            borderwidth=1,
            font=("tahoma", "8", "normal"),
        )
        label.pack(ipadx=1)

    def hide_tip(self, event=None):
        """ツールチップ非表示"""

        if self.tip_window:
            self.tip_window.destroy()
        self.tip_window = None


root = tk.Tk()
label = tk.Label(root, text="これはツールチップ付きラベル")
label.pack(padx=20, pady=20)

# テキストをツールチップに表示
ToolTip(label, "ツールチップに表示する文字列")

root.mainloop()

説明

ツールチップ用のウィジェットもあるらしいですが、今回はToplevelウィジェットを使用して作ります。

クラスの初期設定

クラス「ToolTip」を作成します。
コンストラクタの引数でwidgetとtextを取得して、メンバ変数に設定します。

self.widgetにはクラス「ToolTip」の親ウィジェットとなるラベルオブジェクトが格納されます。
このラベルオブジェクトはメインウィンドウに表示されるラベルを指します。
self.textにはツールチップに表示する文字列が格納されます。

self.widget.bind("<Enter>", self.show_tip)で、メインウィンドウのラベルに対してマウスオーバー処理を設定します。
<Enter>tkinterのイベントアクションで、マウスオーバーした際にself.show_tipが処理されるようになります。

self.widget.bind("<Leave>", self.hide_tip)で、マウスポインターがメインウィンドウのラベルから離れた際の処理を設定します。
<Leave>もイベントアクションで、マウスポインターがラベルから離れた際にself.hide_tipが処理されます。

class ToolTip:
    def __init__(self, widget: tk.Label, text: str):
        self.widget = widget
        self.text = text
        self.tip_window = None
        # マウスオーバーメソッドをバインド
        self.widget.bind("<Enter>", self.show_tip)
        # マウスリーブメソッドをバインド
        self.widget.bind("<Leave>", self.hide_tip)


ツールチップ表示関数

関数「show_tip」でマウスオーバーした際の処理を設定します。
if self.tip_window or not self.text: return では、ツールチップオブジェクトがすでに存在する、またはツールチップの文字列が設定されていない場合、ツールチップを作成しないようにしています。

x = self.widget.winfo_rootx() + 20y = self.widget.winfo_rooty() + 20で、ツールチップを表示する位置を取得します。
winfo_rootx()winfo_rooty()はメインウィンドウに対するウィジェットの位置を取得します。
winfo_rootx()がX座標(横方向)、winfo_rooty()がY座標(縦方向)の位置です。
+ 20とすることで、メインウィンドウラベルの右に20ピクセル、下に20ピクセルの位置にツールチップを表示します。

self.tip_window = tk.Toplevel(self.widget)で、ツールチップを作成します。

wm_overrideredirect(True)を設定することで、ウィンドウの枠、タイトルバー、最大最小化ボタン、閉じるボタンを非表示にします。
wm_overrideredirect(True)を設定することでツールチップらしい見た目になります。

wm_geometry(f"+{x}+{y}")ツールチップの表示位置を設定します。

tk.Label(~)で、ツールチップに表示する文字列を設定します。
今回は背景色を黄色にすることで、よりツールチップらしい見た目にしています。  

    def show_tip(self, event=None):
        """ツールチップ表示"""

        # ツールチップが既に存在する or 表示文字列が設定されていない場合、表示処理をしない
        if self.tip_window or not self.text:
            return

        # ツールチップを表示する位置を取得
        x = self.widget.winfo_rootx() + 20
        y = self.widget.winfo_rooty() + 20
        # ツールチップウィンドウを作成
        self.tip_window = tk.Toplevel(self.widget)
        # ツールチップウィンドウの枠を削除
        self.tip_window.wm_overrideredirect(True)
        # ツールチップウィンドウの表示位置を設定
        self.tip_window.wm_geometry(f"+{x}+{y}")
        label = tk.Label(
            self.tip_window,
            text=self.text,
            justify="left",
            background="#ffffe0",
            relief="solid",
            borderwidth=1,
            font=("tahoma", "8", "normal"),
        )
        label.pack(ipadx=1)

ツールチップ非表示関数

関数「hide_tip」で、メインウィンドウラベルからマウスポインターが離れた際の処理を設定します。
if self.tip_window: self.tip_window.destroy() で、ツールチップオブジェクトを削除します。これでマウスポインターが離れた際にツールチップを非表示できます。

    def hide_tip(self, event=None):
        """ツールチップ非表示"""

        if self.tip_window:
            self.tip_window.destroy()
        self.tip_window = None

処理実行

root = tk.Tk()tkinterを作成し、label = tk.Label(root, text="これはツールチップ付きラベル")でメインウィンドウにラベルを表示します。

ToolTip(label, "ツールチップに表示する文字列")で、ツールチップインスタンスを作成します。

root = tk.Tk()
label = tk.Label(root, text="これはツールチップ付きラベル")
label.pack(padx=20, pady=20)

# テキストをツールチップに表示
ToolTip(label, "ツールチップに表示する文字列")

root.mainloop()


「これはツールチップ付きラベル」にマウスオーバーでツールチップが表示されるようになりました。