如何在 Tkinter 中显示工具提示?
- 2025-03-05 09:14:00
- admin 原创
- 65
问题描述:
工具提示是当鼠标悬停在小部件上一定时间时弹出的小段文本。
如何向我的tkinter
Python 应用程序添加工具提示消息?
解决方案 1:
我尝试了ars提到的博客文章中的代码,也尝试了IDLE lib中的代码。
虽然两种方法都可以,但我不喜欢 IDLE 的工具提示大小受限(必须手动输入新行作为单独的列表),以及提示如何立即出现在博客文章的代码中。
所以我把两者结合起来。它允许您指定包裹长度和悬停时间,而对每个都没有任何限制:
""" tk_ToolTip_class101.py
gives a Tkinter widget a tooltip as the mouse is above the widget
tested with Python27 and Python34 by vegaseat 09sep2014
www.daniweb.com/programming/software-development/code/484591/a-tooltip-class-for-tkinter
Modified to include a delay time by Victor Zaccardo, 25mar16
"""
try:
# for Python2
import Tkinter as tk
except ImportError:
# for Python3
import tkinter as tk
class CreateToolTip(object):
"""
create a tooltip for a given widget
"""
def __init__(self, widget, text='widget info'):
self.waittime = 500 #miliseconds
self.wraplength = 180 #pixels
self.widget = widget
self.text = text
self.widget.bind("<Enter>", self.enter)
self.widget.bind("<Leave>", self.leave)
self.widget.bind("<ButtonPress>", self.leave)
self.id = None
self.tw = None
def enter(self, event=None):
self.schedule()
def leave(self, event=None):
self.unschedule()
self.hidetip()
def schedule(self):
self.unschedule()
self.id = self.widget.after(self.waittime, self.showtip)
def unschedule(self):
id = self.id
self.id = None
if id:
self.widget.after_cancel(id)
def showtip(self, event=None):
x = y = 0
x, y, cx, cy = self.widget.bbox("insert")
x += self.widget.winfo_rootx() + 25
y += self.widget.winfo_rooty() + 20
# creates a toplevel window
self.tw = tk.Toplevel(self.widget)
# Leaves only the label and removes the app window
self.tw.wm_overrideredirect(True)
self.tw.wm_geometry("+%d+%d" % (x, y))
label = tk.Label(self.tw, text=self.text, justify='left',
background="#ffffff", relief='solid', borderwidth=1,
wraplength = self.wraplength)
label.pack(ipadx=1)
def hidetip(self):
tw = self.tw
self.tw= None
if tw:
tw.destroy()
# testing ...
if __name__ == '__main__':
root = tk.Tk()
btn1 = tk.Button(root, text="button 1")
btn1.pack(padx=10, pady=5)
button1_ttp = CreateToolTip(btn1, \n 'Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, '
'consectetur, adipisci velit. Neque porro quisquam est qui dolorem ipsum '
'quia dolor sit amet, consectetur, adipisci velit. Neque porro quisquam '
'est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit.')
btn2 = tk.Button(root, text="button 2")
btn2.pack(padx=10, pady=5)
button2_ttp = CreateToolTip(btn2, \n "First thing's first, I'm the realest. Drop this and let the whole world "
"feel it. And I'm still in the Murda Bizness. I could hold you down, like "
"I'm givin' lessons in physics. You should want a bad Vic like this.")
root.mainloop()
截屏:
解决方案 2:
Python 3.7+ 中的一个简单解决方案
import tkinter as tk
from idlelib.tooltip import Hovertip
app = tk.Tk()
myBtn = tk.Button(app,text='?')
myBtn.pack(pady=30)
myTip = Hovertip(myBtn,'This is
a multiline tooltip.')
app.mainloop()
解决方案 3:
Tkinter 的Pmw 工具包中的Pmw.Balloon类将绘制工具提示。
还请查看这篇博客文章,它改编了 IDLE 中的一些代码,用于使用 Tkinter 显示工具提示。
解决方案 4:
首先,我非常喜欢Alberto Vassena 的工具提示,并尝试在他的帖子中评论此错误更正,但作为新用户,我没有足够的积分来发表评论,所以我正在做出回答。我希望这是可以接受的。
Alberto Vassena 的出色回答和改进的工具提示中有一个非常小的错误。
错误:对于实际的标签,他的代码调用的是 ttk.Label 而不是 tk.Label,这导致工具提示框被呈现,但是实际文本不会被呈现,直到发生进一步的 UI 事件(例如另一次鼠标移动或键盘事件)。
以下是完整复制和粘贴的更正代码:
import tkinter as tk
import tkinter.ttk as ttk
class Tooltip:
'''
It creates a tooltip for a given widget as the mouse goes on it.
see:
http://stackoverflow.com/questions/3221956/
what-is-the-simplest-way-to-make-tooltips-
in-tkinter/36221216#36221216
http://www.daniweb.com/programming/software-development/
code/484591/a-tooltip-class-for-tkinter
- Originally written by vegaseat on 2014.09.09.
- Modified to include a delay time by Victor Zaccardo on 2016.03.25.
- Modified
- to correct extreme right and extreme bottom behavior,
- to stay inside the screen whenever the tooltip might go out on
the top but still the screen is higher than the tooltip,
- to use the more flexible mouse positioning,
- to add customizable background color, padding, waittime and
wraplength on creation
by Alberto Vassena on 2016.11.05.
Tested on Ubuntu 16.04/16.10, running Python 3.5.2
TODO: themes styles support
'''
def __init__(self, widget,
*,
bg='#FFFFEA',
pad=(5, 3, 5, 3),
text='widget info',
waittime=400,
wraplength=250):
self.waittime = waittime # in miliseconds, originally 500
self.wraplength = wraplength # in pixels, originally 180
self.widget = widget
self.text = text
self.widget.bind("<Enter>", self.onEnter)
self.widget.bind("<Leave>", self.onLeave)
self.widget.bind("<ButtonPress>", self.onLeave)
self.bg = bg
self.pad = pad
self.id = None
self.tw = None
def onEnter(self, event=None):
self.schedule()
def onLeave(self, event=None):
self.unschedule()
self.hide()
def schedule(self):
self.unschedule()
self.id = self.widget.after(self.waittime, self.show)
def unschedule(self):
id_ = self.id
self.id = None
if id_:
self.widget.after_cancel(id_)
def show(self):
def tip_pos_calculator(widget, label,
*,
tip_delta=(10, 5), pad=(5, 3, 5, 3)):
w = widget
s_width, s_height = w.winfo_screenwidth(), w.winfo_screenheight()
width, height = (pad[0] + label.winfo_reqwidth() + pad[2],
pad[1] + label.winfo_reqheight() + pad[3])
mouse_x, mouse_y = w.winfo_pointerxy()
x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
x2, y2 = x1 + width, y1 + height
x_delta = x2 - s_width
if x_delta < 0:
x_delta = 0
y_delta = y2 - s_height
if y_delta < 0:
y_delta = 0
offscreen = (x_delta, y_delta) != (0, 0)
if offscreen:
if x_delta:
x1 = mouse_x - tip_delta[0] - width
if y_delta:
y1 = mouse_y - tip_delta[1] - height
offscreen_again = y1 < 0 # out on the top
if offscreen_again:
# No further checks will be done.
# TIP:
# A further mod might automagically augment the
# wraplength when the tooltip is too high to be
# kept inside the screen.
y1 = 0
return x1, y1
bg = self.bg
pad = self.pad
widget = self.widget
# creates a toplevel window
self.tw = tk.Toplevel(widget)
# Leaves only the label and removes the app window
self.tw.wm_overrideredirect(True)
win = tk.Frame(self.tw,
background=bg,
borderwidth=0)
label = tk.Label(win,
text=self.text,
justify=tk.LEFT,
background=bg,
relief=tk.SOLID,
borderwidth=0,
wraplength=self.wraplength)
label.grid(padx=(pad[0], pad[2]),
pady=(pad[1], pad[3]),
sticky=tk.NSEW)
win.grid()
x, y = tip_pos_calculator(widget, label)
self.tw.wm_geometry("+%d+%d" % (x, y))
def hide(self):
tw = self.tw
if tw:
tw.destroy()
self.tw = None
if __name__ == '__main__':
import random
def further_text():
# texts generated at http://lorem-ipsum.perbang.dk/
short_text = ('Lorem ipsum dolor sit amet, mauris tellus, '
'porttitor torquent eu. Magna aliquet lorem, '
'cursus sit ac, in in. Dolor aliquet, cum integer. '
'Proin aliquet, porttitor pulvinar mauris. Tellus '
'lectus, amet cras, neque lacus quis. Malesuada '
'nibh. Eleifend nam, in eget a. Nec turpis, erat '
'wisi semper')
medium_text = ('Lorem ipsum dolor sit amet, suspendisse aenean '
'ipsum sollicitudin, pellentesque nunc ultrices ac '
'ut, arcu elit turpis senectus convallis. Ac orci '
'pretium sed gravida, tortor nulla felis '
'consectetuer, mauris egestas est erat. Ut enim '
'tellus at diam, ac sagittis vel proin. Massa '
'eleifend orci tortor sociis, scelerisque in pede '
'metus phasellus, est tempor gravida nam, ante '
'fusce sem tempor. Mi diam auctor vel pede, mus '
'non mi luctus luctus, lectus sit varius repellat '
'eu')
long_text = ('Lorem ipsum dolor sit amet, velit eu nam cursus '
'quisque gravida sollicitudin, felis arcu interdum '
'error quam quis massa, et velit libero ligula est '
'donec. Suspendisse fringilla urna ridiculus dui '
'volutpat justo, quisque nisl eget sed blandit '
'egestas, libero nullam magna sem dui nam, auctor '
'vehicula nunc arcu vel sed dictum, tincidunt vitae '
'id tristique aptent platea. Lacus eros nec proin '
'morbi sollicitudin integer, montes suspendisse '
'augue lorem iaculis sed, viverra sed interdum eget '
'ut at pulvinar, turpis vivamus ac pharetra nulla '
'maecenas ut. Consequat dui condimentum lectus nulla '
'vitae, nam consequat fusce ac facilisis eget orci, '
'cras enim donec aenean sed dolor aliquam, elit '
'lorem in a nec fringilla, malesuada curabitur diam '
'nonummy nisl nibh ipsum. In odio nunc nec porttitor '
'ipsum, nunc ridiculus platea wisi turpis praesent '
'vestibulum, suspendisse hendrerit amet quis vivamus '
'adipiscing elit, ut dolor nec nonummy mauris nec '
'libero, ad rutrum id tristique facilisis sed '
'ultrices. Convallis velit posuere mauris lectus sit '
'turpis, lobortis volutpat et placerat leo '
'malesuada, vulputate id maecenas at a volutpat '
'vulputate, est augue nec proin ipsum pellentesque '
'fringilla. Mattis feugiat metus ultricies repellat '
'dictum, suspendisse erat rhoncus ultricies in ipsum, '
'nulla ante pellentesque blandit ligula sagittis '
'ultricies, sed tortor sodales pede et duis platea')
text = random.choice([short_text, medium_text, long_text, long_text])
return '
Further info: ' + text
def main_01(wraplength=200):
# alias
stuff = further_text
root = tk.Tk()
frame = ttk.Frame(root)
btn_ne = ttk.Button(frame, text='North East')
btn_se = ttk.Button(frame, text='South East')
btn_sw = ttk.Button(frame, text='South West')
btn_nw = ttk.Button(frame, text='North West')
btn_center = ttk.Button(frame, text='Center')
btn_n = ttk.Button(frame, text='North')
btn_e = ttk.Button(frame, text='East')
btn_s = ttk.Button(frame, text='South')
btn_w = ttk.Button(frame, text='West')
Tooltip(btn_nw, text='North West' + stuff(), wraplength=wraplength)
Tooltip(btn_ne, text='North East' + stuff(), wraplength=wraplength)
Tooltip(btn_se, text='South East' + stuff(), wraplength=wraplength)
Tooltip(btn_sw, text='South West' + stuff(), wraplength=wraplength)
Tooltip(btn_center, text='Center' + stuff(), wraplength=wraplength)
Tooltip(btn_n, text='North' + stuff(), wraplength=wraplength)
Tooltip(btn_e, text='East' + stuff(), wraplength=wraplength)
Tooltip(btn_s, text='South' + stuff(), wraplength=wraplength)
Tooltip(btn_w, text='West' + stuff(), wraplength=wraplength)
r = 0
c = 0
pad = 10
btn_nw.grid(row=r, column=c, padx=pad, pady=pad, sticky=tk.NW)
btn_n.grid(row=r, column=c + 1, padx=pad, pady=pad, sticky=tk.N)
btn_ne.grid(row=r, column=c + 2, padx=pad, pady=pad, sticky=tk.NE)
r += 1
btn_w.grid(row=r, column=c + 0, padx=pad, pady=pad, sticky=tk.W)
btn_center.grid(row=r, column=c + 1, padx=pad, pady=pad,
sticky=tk.NSEW)
btn_e.grid(row=r, column=c + 2, padx=pad, pady=pad, sticky=tk.E)
r += 1
btn_sw.grid(row=r, column=c, padx=pad, pady=pad, sticky=tk.SW)
btn_s.grid(row=r, column=c + 1, padx=pad, pady=pad, sticky=tk.S)
btn_se.grid(row=r, column=c + 2, padx=pad, pady=pad, sticky=tk.SE)
frame.grid(sticky=tk.NSEW)
for i in (0, 2):
frame.rowconfigure(i, weight=1)
frame.columnconfigure(i, weight=1)
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
root.title('Tooltip wraplength = {}'.format(wraplength))
root.mainloop()
def main():
print('Trying out three different wraplengths:')
for i, wl in enumerate((200, 250, 400), 1):
print(' ', i)
main_01(wl)
print('Done.')
main()
解决方案 5:
我不建议使用Tix
小部件,因为Tix
它基本上不再受支持并且通常会导致很多问题。
以下是直接从 Python 模块中获取的工具提示示例idlelib
:
# general purpose 'tooltip' routines - currently unused in idlefork
# (although the 'calltips' extension is partly based on this code)
# may be useful for some purposes in (or almost in ;) the current project scope
# Ideas gleaned from PySol
from tkinter import *
class ToolTipBase:
def __init__(self, button):
self.button = button
self.tipwindow = None
self.id = None
self.x = self.y = 0
self._id1 = self.button.bind("<Enter>", self.enter)
self._id2 = self.button.bind("<Leave>", self.leave)
self._id3 = self.button.bind("<ButtonPress>", self.leave)
def enter(self, event=None):
self.schedule()
def leave(self, event=None):
self.unschedule()
self.hidetip()
def schedule(self):
self.unschedule()
self.id = self.button.after(1500, self.showtip)
def unschedule(self):
id = self.id
self.id = None
if id:
self.button.after_cancel(id)
def showtip(self):
if self.tipwindow:
return
# The tip window must be completely outside the button;
# otherwise when the mouse enters the tip window we get
# a leave event and it disappears, and then we get an enter
# event and it reappears, and so on forever :-(
x = self.button.winfo_rootx() + 20
y = self.button.winfo_rooty() + self.button.winfo_height() + 1
self.tipwindow = tw = Toplevel(self.button)
tw.wm_overrideredirect(1)
tw.wm_geometry("+%d+%d" % (x, y))
self.showcontents()
def showcontents(self, text="Your text here"):
# Override this in derived class
label = Label(self.tipwindow, text=text, justify=LEFT,
background="#ffffe0", relief=SOLID, borderwidth=1)
label.pack()
def hidetip(self):
tw = self.tipwindow
self.tipwindow = None
if tw:
tw.destroy()
class ToolTip(ToolTipBase):
def __init__(self, button, text):
ToolTipBase.__init__(self, button)
self.text = text
def showcontents(self):
ToolTipBase.showcontents(self, self.text)
class ListboxToolTip(ToolTipBase):
def __init__(self, button, items):
ToolTipBase.__init__(self, button)
self.items = items
def showcontents(self):
listbox = Listbox(self.tipwindow, background="#ffffe0")
listbox.pack()
for item in self.items:
listbox.insert(END, item)
您也可以直接导入模块并使用它:
from idlelib.tooltip import * ##corrected wrong import
def main():
root = Tk()
b = Button(root, text="Hello", command=root.destroy)
b.pack()
root.update()
tip = ListboxToolTip(b, ["Hello", "world"])
root.mainloop()
if __name__ == '__main__':
main()
我使用的是Python 3.4,其他Python发行版可能不包含此ToolTip
模块。
解决方案 6:
由于您使用的是 Windows 7,您的 Python 安装很可能已经包含Tix。使用 Tix.Balloon 小部件。示例代码存在于 Python 源代码树中。
基本上,您创建一个Tix.Balloon
小部件,通过其方法将其绑定到其他小部件.bind_widget
,并使用其参数提供气球消息balloonmsg
。
解决方案 7:
我修改了crxguy52建议的Tooltip类。下面的类现在几乎可以在任何情况下工作,无论您需要在哪里实例化它: NW、N、NE、E、SE、S、SW、W。
我的课程目前无法管理的唯一情况是工具提示高于整个屏幕(可能非常罕见,但通过手动传递更大的包裹长度来加宽它也可以立即解决这种情况)。
import tkinter as tk
import tkinter.ttk as ttk
class Tooltip:
'''
It creates a tooltip for a given widget as the mouse goes on it.
see:
https://stackoverflow.com/questions/3221956/
what-is-the-simplest-way-to-make-tooltips-
in-tkinter/36221216#36221216
http://www.daniweb.com/programming/software-development/
code/484591/a-tooltip-class-for-tkinter
- Originally written by vegaseat on 2014.09.09.
- Modified to include a delay time by Victor Zaccardo on 2016.03.25.
- Modified
- to correct extreme right and extreme bottom behavior,
- to stay inside the screen whenever the tooltip might go out on
the top but still the screen is higher than the tooltip,
- to use the more flexible mouse positioning,
- to add customizable background color, padding, waittime and
wraplength on creation
by Alberto Vassena on 2016.11.05.
Tested on Ubuntu 16.04/16.10, running Python 3.5.2
TODO: themes styles support
'''
def __init__(self, widget,
*,
bg='#FFFFEA',
pad=(5, 3, 5, 3),
text='widget info',
waittime=400,
wraplength=250):
self.waittime = waittime # in miliseconds, originally 500
self.wraplength = wraplength # in pixels, originally 180
self.widget = widget
self.text = text
self.widget.bind("<Enter>", self.onEnter)
self.widget.bind("<Leave>", self.onLeave)
self.widget.bind("<ButtonPress>", self.onLeave)
self.bg = bg
self.pad = pad
self.id = None
self.tw = None
def onEnter(self, event=None):
self.schedule()
def onLeave(self, event=None):
self.unschedule()
self.hide()
def schedule(self):
self.unschedule()
self.id = self.widget.after(self.waittime, self.show)
def unschedule(self):
id_ = self.id
self.id = None
if id_:
self.widget.after_cancel(id_)
def show(self):
def tip_pos_calculator(widget, label,
*,
tip_delta=(10, 5), pad=(5, 3, 5, 3)):
w = widget
s_width, s_height = w.winfo_screenwidth(), w.winfo_screenheight()
width, height = (pad[0] + label.winfo_reqwidth() + pad[2],
pad[1] + label.winfo_reqheight() + pad[3])
mouse_x, mouse_y = w.winfo_pointerxy()
x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
x2, y2 = x1 + width, y1 + height
x_delta = x2 - s_width
if x_delta < 0:
x_delta = 0
y_delta = y2 - s_height
if y_delta < 0:
y_delta = 0
offscreen = (x_delta, y_delta) != (0, 0)
if offscreen:
if x_delta:
x1 = mouse_x - tip_delta[0] - width
if y_delta:
y1 = mouse_y - tip_delta[1] - height
offscreen_again = y1 < 0 # out on the top
if offscreen_again:
# No further checks will be done.
# TIP:
# A further mod might automagically augment the
# wraplength when the tooltip is too high to be
# kept inside the screen.
y1 = 0
return x1, y1
bg = self.bg
pad = self.pad
widget = self.widget
# creates a toplevel window
self.tw = tk.Toplevel(widget)
# Leaves only the label and removes the app window
self.tw.wm_overrideredirect(True)
win = tk.Frame(self.tw,
background=bg,
borderwidth=0)
label = ttk.Label(win,
text=self.text,
justify=tk.LEFT,
background=bg,
relief=tk.SOLID,
borderwidth=0,
wraplength=self.wraplength)
label.grid(padx=(pad[0], pad[2]),
pady=(pad[1], pad[3]),
sticky=tk.NSEW)
win.grid()
x, y = tip_pos_calculator(widget, label)
self.tw.wm_geometry("+%d+%d" % (x, y))
def hide(self):
tw = self.tw
if tw:
tw.destroy()
self.tw = None
if __name__ == '__main__':
import random
def further_text():
# texts generated at http://lorem-ipsum.perbang.dk/
short_text = ('Lorem ipsum dolor sit amet, mauris tellus, '
'porttitor torquent eu. Magna aliquet lorem, '
'cursus sit ac, in in. Dolor aliquet, cum integer. '
'Proin aliquet, porttitor pulvinar mauris. Tellus '
'lectus, amet cras, neque lacus quis. Malesuada '
'nibh. Eleifend nam, in eget a. Nec turpis, erat '
'wisi semper')
medium_text = ('Lorem ipsum dolor sit amet, suspendisse aenean '
'ipsum sollicitudin, pellentesque nunc ultrices ac '
'ut, arcu elit turpis senectus convallis. Ac orci '
'pretium sed gravida, tortor nulla felis '
'consectetuer, mauris egestas est erat. Ut enim '
'tellus at diam, ac sagittis vel proin. Massa '
'eleifend orci tortor sociis, scelerisque in pede '
'metus phasellus, est tempor gravida nam, ante '
'fusce sem tempor. Mi diam auctor vel pede, mus '
'non mi luctus luctus, lectus sit varius repellat '
'eu')
long_text = ('Lorem ipsum dolor sit amet, velit eu nam cursus '
'quisque gravida sollicitudin, felis arcu interdum '
'error quam quis massa, et velit libero ligula est '
'donec. Suspendisse fringilla urna ridiculus dui '
'volutpat justo, quisque nisl eget sed blandit '
'egestas, libero nullam magna sem dui nam, auctor '
'vehicula nunc arcu vel sed dictum, tincidunt vitae '
'id tristique aptent platea. Lacus eros nec proin '
'morbi sollicitudin integer, montes suspendisse '
'augue lorem iaculis sed, viverra sed interdum eget '
'ut at pulvinar, turpis vivamus ac pharetra nulla '
'maecenas ut. Consequat dui condimentum lectus nulla '
'vitae, nam consequat fusce ac facilisis eget orci, '
'cras enim donec aenean sed dolor aliquam, elit '
'lorem in a nec fringilla, malesuada curabitur diam '
'nonummy nisl nibh ipsum. In odio nunc nec porttitor '
'ipsum, nunc ridiculus platea wisi turpis praesent '
'vestibulum, suspendisse hendrerit amet quis vivamus '
'adipiscing elit, ut dolor nec nonummy mauris nec '
'libero, ad rutrum id tristique facilisis sed '
'ultrices. Convallis velit posuere mauris lectus sit '
'turpis, lobortis volutpat et placerat leo '
'malesuada, vulputate id maecenas at a volutpat '
'vulputate, est augue nec proin ipsum pellentesque '
'fringilla. Mattis feugiat metus ultricies repellat '
'dictum, suspendisse erat rhoncus ultricies in ipsum, '
'nulla ante pellentesque blandit ligula sagittis '
'ultricies, sed tortor sodales pede et duis platea')
text = random.choice([short_text, medium_text, long_text, long_text])
return '
Further info: ' + text
def main_01(wraplength=200):
# alias
stuff = further_text
root = tk.Tk()
frame = ttk.Frame(root)
btn_ne = ttk.Button(frame, text='North East')
btn_se = ttk.Button(frame, text='South East')
btn_sw = ttk.Button(frame, text='South West')
btn_nw = ttk.Button(frame, text='North West')
btn_center = ttk.Button(frame, text='Center')
btn_n = ttk.Button(frame, text='North')
btn_e = ttk.Button(frame, text='East')
btn_s = ttk.Button(frame, text='South')
btn_w = ttk.Button(frame, text='West')
Tooltip(btn_nw, text='North West' + stuff(), wraplength=wraplength)
Tooltip(btn_ne, text='North East' + stuff(), wraplength=wraplength)
Tooltip(btn_se, text='South East' + stuff(), wraplength=wraplength)
Tooltip(btn_sw, text='South West' + stuff(), wraplength=wraplength)
Tooltip(btn_center, text='Center' + stuff(), wraplength=wraplength)
Tooltip(btn_n, text='North' + stuff(), wraplength=wraplength)
Tooltip(btn_e, text='East' + stuff(), wraplength=wraplength)
Tooltip(btn_s, text='South' + stuff(), wraplength=wraplength)
Tooltip(btn_w, text='West' + stuff(), wraplength=wraplength)
r = 0
c = 0
pad = 10
btn_nw.grid(row=r, column=c, padx=pad, pady=pad, sticky=tk.NW)
btn_n.grid(row=r, column=c + 1, padx=pad, pady=pad, sticky=tk.N)
btn_ne.grid(row=r, column=c + 2, padx=pad, pady=pad, sticky=tk.NE)
r += 1
btn_w.grid(row=r, column=c + 0, padx=pad, pady=pad, sticky=tk.W)
btn_center.grid(row=r, column=c + 1, padx=pad, pady=pad,
sticky=tk.NSEW)
btn_e.grid(row=r, column=c + 2, padx=pad, pady=pad, sticky=tk.E)
r += 1
btn_sw.grid(row=r, column=c, padx=pad, pady=pad, sticky=tk.SW)
btn_s.grid(row=r, column=c + 1, padx=pad, pady=pad, sticky=tk.S)
btn_se.grid(row=r, column=c + 2, padx=pad, pady=pad, sticky=tk.SE)
frame.grid(sticky=tk.NSEW)
for i in (0, 2):
frame.rowconfigure(i, weight=1)
frame.columnconfigure(i, weight=1)
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
root.title('Tooltip wraplength = {}'.format(wraplength))
root.mainloop()
def main():
print('Trying out three different wraplengths:')
for i, wl in enumerate((200, 250, 400), 1):
print(' ', i)
main_01(wl)
print('Done.')
main()
HTH。我在这里发布了一个CanvasTooltip类,它允许将工具提示绑定到在 tkinter Canvas 内创建的项目。
解决方案 8:
尽管答案有多个,但我还是想发表一下我的看法。
class ToolTip:
def __init__(self,widget,text=None):
def on_enter(event):
self.tooltip=tk.Toplevel()
self.tooltip.overrideredirect(True)
self.tooltip.geometry(f'+{event.x_root+15}+{event.y_root+10}')
self.label=tk.Label(self.tooltip,text=self.text)
self.label.pack()
def on_leave(event):
self.tooltip.destroy()
self.widget=widget
self.text=text
self.widget.bind('<Enter>',on_enter)
self.widget.bind('<Leave>',on_leave)
这是一个相对于光标位置显示的基本工具提示。
解决方案 9:
from tkinter import *
from tkinter.tix import *
root = Tk()
btn1 = Button(root, text="hello")
btn1.grid(row=0, column=0)
balloon = Balloon(root, bg="white", title="Help")
balloon.bind_widget(btn1, balloonmsg="Click to Exit")
root.mainloop()
解决方案 10:
这一系列答案对我非常有用,我想分享我对这个社区工作的改进。在我的用例中,几个嵌套的小部件可以有工具提示。因此,以前的实现让所有工具提示同时出现,堆叠它们并使其笨拙且无法阅读。我修改后的工具提示使用一个通用信号量来同步所有工具提示。(此外,我重新格式化了文档字符串以使其在 sphinx 渲染中更美观)
class Semaphore:
"A semaphore letting several tooltips synchronising themself."
def __init__(self):
self.state = None
self.held = False
def request(self, ident):
if self.held:
return False
self.state = ident
return True
def hold(self, ident):
if self.held:
return False
if self.state is not ident:
return False
self.held = True
return True
def release(self, ident):
if self.held and self.state is ident:
self.held = False
self.state = None
_default_sem = Semaphore()
class Tooltip:
"""Create a floating tooltip next to the attached widget.
Credits:
- Originally written by vegaseat on 2014.09.09 (`blog post`_).
- Modified to include a delay time by Victor Zaccardo on 2016.03.25 (`stackoverflow answer 1`_).
- Modified by Alberto Vassena on 2016.11.05 (`stackoverflow answer 2`_):
- to correct extreme right and extreme bottom behavior,
- to stay inside the screen whenever the tooltip might go out on
the top but still the screen is higher than the tooltip,
- to use the more flexible mouse positioning,
- to add customizable background color, padding, waittime and
wraplength on creation
- Modified to fix a scheduling bug by Erik Bethke on 2016.12.29 (`stackoverflow answer 3`_).
- Modified by Théo Cavignac to prevent more than one visible tooltip at
a time, causing superpositions of tooltips in complex widget tree,
on 2022.09.04 (in `tkgen sources`_).
Tested on Archlinux (kernel 6.2.2), running Python 3.10.9
.. _blog post: http://www.daniweb.com/programming/software-development/code/484591/a-tooltip-class-for-tkinter
.. _stackoverflow answer 1: https://stackoverflow.com/a/36221216/6324751
.. _stackoverflow answer 2: https://stackoverflow.com/a/41079350/6324751
.. _stackoverflow answer 3: https://stackoverflow.com/a/41381685/6324751
.. _tkgen sources: https://git.sr.ht/~lattay/python-tkgen/tree/bdb9ba3c1ee173d2765966cd23f5acdb6f07007f/item/tkform/tooltip.py#L36-197
"""
def __init__(
self,
widget,
*,
bg="#FFFFEA",
pad=(5, 3, 5, 3),
text="widget info",
waittime=200,
wraplength=250,
sem=_default_sem
):
self.waittime = waittime # in miliseconds, originally 500
self.wraplength = wraplength # in pixels, originally 180
self.widget = widget
self.text = text
self.widget.bind("<Enter>", self.onEnter)
self.widget.bind("<Leave>", self.onLeave)
self.widget.bind("<ButtonPress>", self.onLeave)
self.bg = bg
self.pad = pad
self.id = None
self.tw = None
self.ident = object()
self.sem = sem
def onEnter(self, event=None):
self.schedule()
def onLeave(self, event=None):
self.unschedule()
self.hide()
def schedule(self):
if self.sem.request(self.ident):
self.unschedule()
self.id = self.widget.after(self.waittime, self.show)
def unschedule(self):
self.sem.release(self.ident)
id_ = self.id
self.id = None
if id_:
self.widget.after_cancel(id_)
def show(self):
if not self.sem.hold(self.ident):
return
def tip_pos_calculator(widget, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)):
w = widget
s_width, s_height = w.winfo_screenwidth(), w.winfo_screenheight()
width, height = (
pad[0] + label.winfo_reqwidth() + pad[2],
pad[1] + label.winfo_reqheight() + pad[3],
)
mouse_x, mouse_y = w.winfo_pointerxy()
x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
x2, y2 = x1 + width, y1 + height
x_delta = x2 - s_width
if x_delta < 0:
x_delta = 0
y_delta = y2 - s_height
if y_delta < 0:
y_delta = 0
offscreen = (x_delta, y_delta) != (0, 0)
if offscreen:
if x_delta:
x1 = mouse_x - tip_delta[0] - width
if y_delta:
y1 = mouse_y - tip_delta[1] - height
offscreen_again = y1 < 0 # out on the top
if offscreen_again:
# No further checks will be done.
# TIP:
# A further mod might automagically augment the
# wraplength when the tooltip is too high to be
# kept inside the screen.
y1 = 0
return x1, y1
bg = self.bg
pad = self.pad
widget = self.widget
# creates a toplevel window
self.tw = tk.Toplevel(widget)
# Leaves only the label and removes the app window
self.tw.wm_overrideredirect(True)
win = tk.Frame(self.tw, background=bg, borderwidth=0)
label = ttk.Label(
win,
text=self.text,
justify=tk.LEFT,
background=bg,
relief=tk.SOLID,
borderwidth=0,
wraplength=self.wraplength,
)
label.grid(padx=(pad[0], pad[2]), pady=(pad[1], pad[3]), sticky=tk.NSEW)
win.grid()
x, y = tip_pos_calculator(widget, label)
self.tw.wm_geometry("+%d+%d" % (x, y))
def hide(self):
tw = self.tw
if tw:
tw.destroy()
self.tw = None
解决方案 11:
tkinter-tooltip
已经很成熟,对我来说非常好用。我可以跳过所有冗长的 tkinter 代码,直接使用代码。
以下是他们的 Hello World:
import tkinter as tk
import tkinter.ttk as ttk
from tktooltip import ToolTip
app = tk.Tk()
b = ttk.Button(app, text="Button")
b.pack()
ToolTip(b, msg="Hover info")
app.mainloop()
扫码咨询,免费领取项目管理大礼包!