1 | class ToolTip: |
---|
2 | |
---|
3 | def __init__(self, master, text='No informations found', delay=1500, **opts): |
---|
4 | self.master = master |
---|
5 | self._opts = {'anchor':'center', 'bd':1, 'bg':'lightyellow', 'delay':delay, 'fg':'black',\ |
---|
6 | 'follow_mouse':0, 'font':None, 'justify':'left', 'padx':4, 'pady':2,\ |
---|
7 | 'relief':'solid', 'state':'normal', 'text':text, 'textvariable':None,\ |
---|
8 | 'width':0, 'wraplength':150} |
---|
9 | self.configure(**opts) |
---|
10 | self._tipwindow = None |
---|
11 | self._id = None |
---|
12 | self._id1 = self.master.bind("<Enter>", self.enter, '+') |
---|
13 | self._id2 = self.master.bind("<Leave>", self.leave, '+') |
---|
14 | self._id3 = self.master.bind("<ButtonPress>", self.leave, '+') |
---|
15 | self._follow_mouse = 0 |
---|
16 | if self._opts['follow_mouse']: |
---|
17 | self._id4 = self.master.bind("<Motion>", self.motion, '+') |
---|
18 | self._follow_mouse = 1 |
---|
19 | |
---|
20 | def configure(self, **opts): |
---|
21 | for key in opts: |
---|
22 | if self._opts.has_key(key): |
---|
23 | self._opts[key] = opts[key] |
---|
24 | else: |
---|
25 | KeyError = 'KeyError: Unknown option: "%s"' %key |
---|
26 | raise KeyError |
---|
27 | |
---|
28 | ## These methods handle the callbacks on "<Enter>", "<Leave>" and "<Motion>" ## |
---|
29 | ## Events on the parent widget; override them if you want to change the widget's behavior--## |
---|
30 | |
---|
31 | def enter(self, event=None): |
---|
32 | self._schedule() |
---|
33 | |
---|
34 | def leave(self, event=None): |
---|
35 | self._unschedule() |
---|
36 | self._hide() |
---|
37 | |
---|
38 | def motion(self, event=None): |
---|
39 | if self._tipwindow and self._follow_mouse: |
---|
40 | x, y = self.coords() |
---|
41 | self._tipwindow.wm_geometry("+%d+%d" % (x, y)) |
---|
42 | |
---|
43 | ## The methods that do the work ## |
---|
44 | |
---|
45 | def _schedule(self): |
---|
46 | self._unschedule() |
---|
47 | if self._opts['state'] == 'disabled': |
---|
48 | return |
---|
49 | self._id = self.master.after(self._opts['delay'], self._show) |
---|
50 | |
---|
51 | def _unschedule(self): |
---|
52 | id = self._id |
---|
53 | self._id = None |
---|
54 | if id: |
---|
55 | self.master.after_cancel(id) |
---|
56 | |
---|
57 | def _show(self): |
---|
58 | if self._opts['state'] == 'disabled': |
---|
59 | self._unschedule() |
---|
60 | return |
---|
61 | if not self._tipwindow: |
---|
62 | self._tipwindow = tw = Tkinter.Toplevel(self.master) |
---|
63 | # Hide the window until we know the geometry |
---|
64 | tw.withdraw() |
---|
65 | tw.wm_overrideredirect(1) |
---|
66 | |
---|
67 | if tw.tk.call("tk", "windowingsystem") == 'aqua': |
---|
68 | tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w, "help", "none") |
---|
69 | |
---|
70 | self.create_contents() |
---|
71 | tw.update_idletasks() |
---|
72 | x, y = self.coords() |
---|
73 | tw.wm_geometry("+%d+%d" % (x, y)) |
---|
74 | tw.deiconify() |
---|
75 | |
---|
76 | def _hide(self): |
---|
77 | tw = self._tipwindow |
---|
78 | self._tipwindow = None |
---|
79 | if tw: |
---|
80 | tw.destroy() |
---|
81 | |
---|
82 | ## These methods might be overridden in derived classes ## |
---|
83 | |
---|
84 | def coords(self): |
---|
85 | # The tip window must be completely outside the master widget; |
---|
86 | # otherwise when the mouse enters the tip window we get |
---|
87 | # a leave event and it disappears, and then we get an enter |
---|
88 | # event and it reappears, and so on forever |
---|
89 | # or we take care that the mouse pointer is always outside the tipwindow |
---|
90 | tw = self._tipwindow |
---|
91 | twx, twy = tw.winfo_reqwidth(), tw.winfo_reqheight() |
---|
92 | w, h = tw.winfo_screenwidth(), tw.winfo_screenheight() |
---|
93 | # Calculate the y coordinate |
---|
94 | if self._follow_mouse: |
---|
95 | y = tw.winfo_pointery() + 20 |
---|
96 | # Make sure the tipwindow is never outside the screen |
---|
97 | if y + twy > h: |
---|
98 | y = y - twy - 30 |
---|
99 | else: |
---|
100 | y = self.master.winfo_rooty() + self.master.winfo_height() + 3 |
---|
101 | if y + twy > h: |
---|
102 | y = self.master.winfo_rooty() - twy - 3 |
---|
103 | # We can use the same x coordinate in both cases |
---|
104 | x = tw.winfo_pointerx() - twx / 2 |
---|
105 | if x < 0: |
---|
106 | x = 0 |
---|
107 | elif x + twx > w: |
---|
108 | x = w - twx |
---|
109 | return x, y |
---|
110 | |
---|
111 | def create_contents(self): |
---|
112 | opts = self._opts.copy() |
---|
113 | for opt in ('delay', 'follow_mouse', 'state'): |
---|
114 | del opts[opt] |
---|
115 | label = Tkinter.Label(self._tipwindow, **opts) |
---|
116 | label.pack() |
---|
117 | |
---|
118 | ## This method generates the informations about the site ## |
---|
119 | |
---|
120 | def get_info(url): |
---|
121 | o = urlparse(url) |
---|
122 | return ('Network location: ' + o.netloc + '\n' + |
---|
123 | 'Path: ' + o.path + '\n' + |
---|
124 | 'Parameters: ' + o.params + '\n' + |
---|
125 | 'Query: ' + o.query + '\n' + |
---|
126 | 'Fragment: ' + o.fragment + '\n' + |
---|
127 | 'Username: ' + o.username + '\n' + |
---|
128 | 'Host name: ' + o.hostname + '\n' + |
---|
129 | 'Port: ' + o.port + '\n') |
---|