1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Tkinter as tk
import ttk
import textwrap
class HoverInfo():
"""Allow to display an info window near a Tkinter widget. Based on
ToolTipBase object from evandrix (idlelib)
Parameters
----------
master : Tkinter widget
Tkinter widget on which the info box will be displayed.
text : str, opt
Text to display in the info window.
width : int, opt
Max width of the info window in character length. Default 40.
duration : int, opt
Time in ms to wait before seing the info window to popup.
Default is 500ms (0.5s)
"""
def __init__(self, master, text='', width=40, duration=500):
self.master = master
if not isinstance(text, str):
raise ValueError('"text" parameter must be a string')
if not isinstance(duration, int):
raise ValueError('"duration" parameter must be an integer')
if not isinstance(width, int):
raise ValueError('"width" parameter must be an integer')
self.text_info = text
self.width = width
self.duration = duration
self.infowindow = None
self.id = None
self.x = self.y = 0
self._id1 = self.master.bind('<Enter>', self.enter)
self._id2 = self.master.bind('<Leave>', self.leave)
self._id3 = self.master.bind('<ButtonPress>', self.leave)
def enter(self, event=None):
self.schedule()
def leave(self, event=None):
self.unschedule()
self.hideinfo()
def schedule(self):
self.unschedule()
self.id = self.master.after(self.duration, self.showinfo)
def unschedule(self):
id = self.id
self.id = None
if id:
self.master.after_cancel(id)
def showinfo(self):
if self.infowindow:
return
# Place the infowindow outside the master
x = self.master.winfo_rootx() + 20
y = self.master.winfo_rooty() + self.master.winfo_height() + 1
self.infowindow = tw = tk.Toplevel(self.master)
tw.wm_overrideredirect(1)
tw.wm_geometry('+%d+%d' % (x, y))
# Wrap text_info to avoid too large infowindow
_text = '\n'.join(textwrap.wrap(self.text_info, width=self.width))
label = tk.Label(self.infowindow, text=_text, justify='left',
background="#E5E5E5", borderwidth=0.5)
label.pack()
def hideinfo(self):
tw = self.infowindow
self.infowindow = None
if tw:
tw.destroy()
class MyApp(tk.Frame):
"""
"""
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
label = tk.Label(self, text='Hover me!', width=15, height=3)
label.pack()
hover = HoverInfo(label, "This is a message displayed when \
mouse's cursor is let more than 0.5s over this widget")
if __name__ == '__main__':
root = tk.Tk()
app = MyApp(root)
app.pack()
root.mainloop() |