【问题标题】:How to add hover feature for text description on a Tkinter button?如何在 Tkinter 按钮上为文本描述添加悬停功能?
【发布时间】:2020-12-20 04:44:16
【问题描述】:

我想在 Tkinter 按钮上添加悬停功能,如果用户悬停鼠标光标,则会显示描述文本。我还想为该描述的出现添加一些延迟,以免造成干扰。

我可以尝试使用按钮的"<Enter>""<Leave>" 绑定到一个函数,并在应用程序的某个角落出现一些“标签”。但这种方法可能不是最优雅的。

【问题讨论】:

    标签: python button tkinter tkinter-layout


    【解决方案1】:

    这是一个使用Pmw(python 巨型小部件)作为工具提示的小 sn-p。

    首先安装它:

    pip install Pmw
    

    那么这里有一个sn-p来了解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 时造成混乱(如果您有任何意图)。有办法解决。

    干杯

    【讨论】:

    • 这太棒了!谢谢!是的,我确实有打算以后转成.exe!
    • @UtpalKumar 也许评论一下这个asnwer,我会帮助你,这是一个很容易解决的问题
    • 请分享您如何解决因“Pmw”库引起的不兼容问题?
    • 不兼容?详细点?
    • 其实这个问题是以后的问题了,暂时先过去吧,反正转换的时候可以问个Q和病态的帮助
    【解决方案2】:

    这可以通过tkinter 轻松完成。通过将EnterLeave 事件添加到您想要添加工具提示的任何内容,我们可以轻松地显示/隐藏我们想要的任何内容,无论我们想要什么。在我的示例中,我使用了精简的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', 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()
    

    【讨论】:

      猜你喜欢
      • 2017-05-29
      • 1970-01-01
      • 1970-01-01
      • 2022-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-23
      • 1970-01-01
      相关资源
      最近更新 更多