How to add hover feature for text description on a Tkinter button?

非 Y 不嫁゛ 提交于 2021-02-05 11:52:37

问题


I want to add a hover feature on a Tkinter button where if the user hovers the mouse cursor then description text displays. I also want to add some delay for that description to appear so that it would not be intrusive.

I can try using the "<Enter>" and "<Leave>" binding of the button to a function and make some "Label" appear in some corner of the app. But this approach may not be the most elegant.


回答1:


Here is a small snippet using Pmw (python mega widgets) for the tool tips.

Firstly start by installing it:

pip install Pmw

Then here is a snippet to understand what Pmw can do:

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()

Hope this gives you a better idea. Keep in mind that Pmw could create a mess while converting the py to an exe later(if you have any intentions to). There is a way around in tho.

Cheers




回答2:


This can be done very easily with tkinter. By adding Enter and Leave events to whatever you want to add a tooltip to, we can easily show/hide whatever we want, wherever we want. In my example I use a stripped-down tk.Toplevel so we can have a simple fade animation, and the tooltip wont be confined to the root window.

#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', 0, '-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, alpha:float, 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()


来源:https://stackoverflow.com/questions/63681382/how-to-add-hover-feature-for-text-description-on-a-tkinter-button

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!