#!/usr/bin/env python3 # Copyright © 2012-13 Qtrac Ltd. All rights reserved. # This program or module is free software: you can redistribute it # and/or modify it under the terms of the GNU General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. It is provided for # educational purposes and is distributed in the hope that it will be # useful, but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # This module is a simplification and adaptation of the code provided by # Michael Lange at http://tkinter.unpy.net/wiki/ToolTip if __name__ == "__main__": # For stand-alone testing with parallel TkUtil import os import sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) import tkinter as tk import tkinter.ttk as ttk import tkinter.font as tkfont import TkUtil class Tooltip: def __init__(self, master, text, delay=1200, showTime=10000, background="lightyellow"): self.master = master self.text = text self.delay = delay self.showTime = showTime self.background = background self.timerId = None self.tip = None self.master.bind("<Enter>", self.enter, "+") self.master.bind("<Leave>", self.leave, "+") def enter(self, event=None): if self.timerId is None and self.tip is None: self.timerId = self.master.after(self.delay, self.show) def leave(self, event=None): if self.timerId is not None: id = self.timerId self.timerId = None self.master.after_cancel(id) self.hide() def hide(self): if self.tip is not None: tip = self.tip self.tip = None tip.destroy() def show(self): self.leave() self.tip = tk.Toplevel(self.master) self.tip.withdraw() # Don't show until we have the geometry self.tip.wm_overrideredirect(True) # No window decorations etc. if TkUtil.mac(): self.tip.tk.call("::tk::unsupported::MacWindowStyle", "style", self.tip._w, "help", "none") label = ttk.Label(self.tip, text=self.text, padding=1, background=self.background, wraplength=480, relief=None if TkUtil.mac() else tk.GROOVE, font=tkfont.nametofont("TkTooltipFont")) label.pack() x, y = self.position() self.tip.wm_geometry("+{}+{}".format(x, y)) self.tip.deiconify() if self.master.winfo_viewable(): self.tip.transient(self.master) self.tip.update_idletasks() self.timerId = self.master.after(self.showTime, self.hide) def position(self): tipx = self.tip.winfo_reqwidth() tipy = self.tip.winfo_reqheight() width = self.tip.winfo_screenwidth() height = self.tip.winfo_screenheight() y = self.master.winfo_rooty() + self.master.winfo_height() if y + tipy > height: y = self.master.winfo_rooty() - tipy x = self.tip.winfo_pointerx() if x < 0: x = 0 elif x + tipx > width: x = width - tipx return x, y if __name__ == "__main__": if sys.stdout.isatty(): application = tk.Tk() application.title("Tooltip") box = tk.Listbox(application) box.insert("end", "This is a listbox") box.pack(side="top") Tooltip(box, text="This is a tooltip with all the options left at " " their default values, so this is what you get if you just " " give a tooltip text") button = tk.Button(application, text="Quit", command=application.quit) button.pack(side="bottom") Tooltip(button, text="Click to Terminate") application.mainloop() else: print("Loaded OK")