讨论了如何为按钮添加工具提示。
how-do-i-display-tooltips-in-tkinter
我知道一个方法(上面的帖子),可以为菜单项添加工具提示。
how-can-i-add-a-tooltip-to-menu-item
我尝试将它们结合起来并对两种方法进行必要的更改。缺点是:我不知道如何可靠地获取菜单项的包围盒。为了解决这个问题,我不得不使用等宽字体TkFixedFont,并对菜单项的边距/边框进行一些假设。这些都在代码中。
tipwin.py
import re
import tkinter as tk
def parse_geometry(g):
m = re.match(r'(\d+)x(\d+)\+(\d+)\+(\d+)', g)
return map(int, m.groups())
class TipWin(tk.Toplevel):
WRAPLENGTH = 180
def __init__(self, parent, start, end, text):
x, y = list(parse_geometry(parent.master.geometry()))[-2:]
self.parent, self.start, self.end, self.text = \
parent, start, end, text
super().__init__(parent)
self.wm_overrideredirect(True)
label = tk.Label(
self, text=self.text, justify='left',
background="#ffffff", relief='solid', borderwidth=1,
wraplength=self.WRAPLENGTH)
self.geometry(f'+{x + start}+{y}')
label.pack(ipadx=1)
def destroy(self):
super().destroy()
menubar.py
import tkinter as tk
from tipwin import TipWin
CW = 8
PAD = 13
class Menu(tk.Menu):
def __init__(self, parent, **kwargs):
super().__init__(parent, **kwargs)
self.parent = parent
self.tiplist = []
self.activetip = -1
self.nexttip = 1
self.bind('<Enter>', self.on_enter)
self.bind('<Motion>', self.on_motion)
self.bind('<Leave>', self.on_leave)
def on_enter(self, event):
self.hidetip()
if self.activetip != 1:
self.showtip(self.activetip, event)
def on_leave(self, event):
self.hidetip()
def on_motion(self, event):
x = event.x
for i in range(len(self.tiplist)):
if self.tiplist[i][0] <= x < self.tiplist[i][1]:
self.showtip(i, event)
return
self.hidetip()
def add_command(self, *args, **kwargs):
tooltip = kwargs.get('tooltip')
if tooltip:
del kwargs['tooltip']
label = kwargs.get('label')
super().add_command(*args, **kwargs)
self.addtip(label, tooltip)
def addtip(self, label, tooltip):
def _w(nc):
return nc * CW + PAD
x1 = self.nexttip
self.nexttip += _w(len(label))
self.tiplist.append((x1, self.nexttip, tooltip))
def showtip(self, i, event):
if self.activetip != -1:
if i != self.activetip:
self.hidetip()
t = self.tiplist[i][2]
if t:
if self.activetip != i:
self.tipwin = TipWin(self, *self.tiplist[i])
self.activetip = i
def hidetip(self):
if self.activetip != -1:
if self.tipwin:
self.tipwin.destroy()
self.tipwin = None
self.activetip = -1
class App(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.title('Menubar')
self.geometry('600x300+400+300')
menubar = Menu(self, tearoff=0)
self.config(menu=menubar)
menubar.add_command(
label='Notes',
font='TkFixedFont',
tooltip='Edit items metadata')
menubar.add_command(
label='Application',
font='TkFixedFont',
tooltip='Save Toplevel windows geometry')
menubar.add_command(
label='Quit',
font='TkFixedFont',
tooltip='Quit')
if __name__ == '__main__':
App().mainloop()
它已经在Python 3.9.2和Debian GNU/Linux 11 (bullseye)上进行了测试。