问题描述
我想在Tkinter按钮上添加一个悬停功能,如果用户将鼠标悬停在该按钮上,则会显示说明文字。我还想为该描述添加一些延迟,以免造成干扰。
我可以尝试将按钮的"<Enter>"
和"<Leave>"
绑定到一个函数上,并在应用程序的某个角落显示一些“标签”。但是这种方法可能不是最优雅的。
解决方法
以下是使用Pmw
(Python大型小部件)作为工具提示的小片段。
首先安装它:
pip install Pmw
然后是以下代码段,以了解Pmw
可以做什么:
from tkinter import *
import Pmw
root = Tk()
Pmw.initialise(root) #initializing it in the root window
l = Label(root,text='Random Text')
l.pack()
b = Button(root,text='Hover me')
b.pack()
tooltip_1 = Pmw.Balloon(root) #Calling the tooltip
tooltip_1.bind(b,'This is the hover Text\nHope you get an idea of whats going on here.') #binding it and assigning a text to it
root.mainloop()
希望这给您一个更好的主意。请记住,Pmw
可能会在以后将py转换为exe时造成混乱(如果有任何意图)。 tho中有一个解决方法。
欢呼
,使用tkinter
可以很容易地做到这一点。通过将Enter
和Leave
事件添加到要向其添加工具提示的任何内容,我们可以轻松地显示/隐藏所需的任何内容。在我的示例中,我使用了简化的tk.Toplevel
,因此我们可以使用简单的淡入淡出动画,并且工具提示将不会局限于根窗口。
#widgets.py
import tkinter as tk,tkinter.ttk as ttk
from typing import Union
Widget = Union[tk.Widget,ttk.Widget]
class ToolTip(tk.Toplevel):
#amount to adjust fade by on every animation frame
FADE_INC:float = .07
#amount of milliseconds to wait before next animation state
FADE_MS :int = 20
def __init__(self,master,**kwargs):
tk.Toplevel.__init__(self,master)
#make window invisible,on the top,and strip all window decorations/features
self.attributes('-alpha','-topmost',True)
self.overrideredirect(1)
#style and create label. you can override style with kwargs
style = dict(bd=2,relief='raised',font='courier 10 bold',bg='#FFFF99',anchor='w')
self.label = tk.Label(self,**{**style,**kwargs})
self.label.grid(row=0,column=0,sticky='w')
#used to determine if an opposing fade is already in progress
self.fout:bool = False
def bind(self,target:Widget,text:str,**kwargs):
#bind Enter(mouseOver) and Leave(mouseOut) events to the target of this tooltip
target.bind('<Enter>',lambda e: self.fadein(0,text,e))
target.bind('<Leave>',lambda e: self.fadeout(1-ToolTip.FADE_INC,e))
def fadein(self,alpha:float,text:str=None,event:tk.Event=None):
#if event and text then this call came from target
#~ we can consider this a "fresh/new" call
if event and text:
#if we are in the middle of fading out jump to end of fade
if self.fout:
self.attributes('-alpha',0)
#indicate that we are fading in
self.fout = False
#assign text to label
self.label.configure(text=f'{text:^{len(text)+2}}')
#update so the proceeding geometry will be correct
self.update()
#x and y offsets
offset_x = event.widget.winfo_width()+2
offset_y = int((event.widget.winfo_height()-self.label.winfo_height())/2)
#get geometry
w = self.label.winfo_width()
h = self.label.winfo_height()
x = event.widget.winfo_rootx()+offset_x
y = event.widget.winfo_rooty()+offset_y
#apply geometry
self.geometry(f'{w}x{h}+{x}+{y}')
#if we aren't fading out,fade in
if not self.fout:
self.attributes('-alpha',alpha)
if alpha < 1:
self.after(ToolTip.FADE_MS,lambda: self.fadein(min(alpha+ToolTip.FADE_INC,1)))
def fadeout(self,event:tk.Event=None):
#if event then this call came from target
#~ we can consider this a "fresh/new" call
if event:
#indicate that we are fading out
self.fout = True
#if we aren't fading in,fade out
if self.fout:
self.attributes('-alpha',alpha)
if alpha > 0:
self.after(ToolTip.FADE_MS,lambda: self.fadeout(max(alpha-ToolTip.FADE_INC,0)))
#main.py ~ EXAMPLE USAGE OOP
import tkinter as tk
from widgets import ToolTip
class Root(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
#instantiate ToolTip
tt = ToolTip(self)
#create first button and bind a tooltip to it
btn = tk.Button(self,text='hover')
btn.grid(column=0,row=0)
tt.bind(btn,'first button is hovered')
#create second button and bind a tooltip to it
btn2 = tk.Button(self,text='hover2')
btn2.grid(column=1,row=0)
tt.bind(btn2,'second button is hovered')
if __name__ == "__main__":
root = Root()
root.title("ToolTip Example")
root.mainloop()
#main.py ~ EXAMPLE USAGE PROCEDURAL
import tkinter as tk
from widgets import ToolTip
if __name__ == "__main__":
root = tk.Tk()
root.title("ToolTip Example")
#instantiate ToolTip
tt = ToolTip(root)
#create first button and bind a tooltip to it
btn = tk.Button(root,text='hover')
btn.grid(column=0,row=0)
tt.bind(btn,'first button is hovered')
#create second button and bind a tooltip to it
btn2 = tk.Button(root,text='hover2')
btn2.grid(column=1,row=0)
tt.bind(btn2,'second button is hovered')
root.mainloop()