Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
tooltip.py191 linesDownload Raw Back to idlelib
1"""Tools for displaying tool-tips.2 3This includes:4 * an abstract base-class for different kinds of tooltips5 * a simple text-only Tooltip class6"""7from tkinter import *8 9 10class TooltipBase:11    """abstract base class for tooltips"""12 13    def __init__(self, anchor_widget):14        """Create a tooltip.15 16        anchor_widget: the widget next to which the tooltip will be shown17 18        Note that a widget will only be shown when showtip() is called.19        """20        self.anchor_widget = anchor_widget21        self.tipwindow = None22 23    def __del__(self):24        self.hidetip()25 26    def showtip(self):27        """display the tooltip"""28        if self.tipwindow:29            return30        self.tipwindow = tw = Toplevel(self.anchor_widget)31        # show no border on the top level window32        tw.wm_overrideredirect(1)33        try:34            # This command is only needed and available on Tk >= 8.4.0 for OSX.35            # Without it, call tips intrude on the typing process by grabbing36            # the focus.37            tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w,38                       "help", "noActivates")39        except TclError:40            pass41 42        self.position_window()43        self.showcontents()44        self.tipwindow.update_idletasks()  # Needed on MacOS -- see #34275.45        self.tipwindow.lift()  # work around bug in Tk 8.5.18+ (issue #24570)46 47    def position_window(self):48        """(re)-set the tooltip's screen position"""49        x, y = self.get_position()50        root_x = self.anchor_widget.winfo_rootx() + x51        root_y = self.anchor_widget.winfo_rooty() + y52        self.tipwindow.wm_geometry("+%d+%d" % (root_x, root_y))53 54    def get_position(self):55        """choose a screen position for the tooltip"""56        # The tip window must be completely outside the anchor widget;57        # otherwise when the mouse enters the tip window we get58        # a leave event and it disappears, and then we get an enter59        # event and it reappears, and so on forever :-(60        #61        # Note: This is a simplistic implementation; sub-classes will likely62        # want to override this.63        return 20, self.anchor_widget.winfo_height() + 164 65    def showcontents(self):66        """content display hook for sub-classes"""67        # See ToolTip for an example68        raise NotImplementedError69 70    def hidetip(self):71        """hide the tooltip"""72        # Note: This is called by __del__, so careful when overriding/extending73        tw = self.tipwindow74        self.tipwindow = None75        if tw:76            try:77                tw.destroy()78            except TclError:  # pragma: no cover79                pass80 81 82class OnHoverTooltipBase(TooltipBase):83    """abstract base class for tooltips, with delayed on-hover display"""84 85    def __init__(self, anchor_widget, hover_delay=1000):86        """Create a tooltip with a mouse hover delay.87 88        anchor_widget: the widget next to which the tooltip will be shown89        hover_delay: time to delay before showing the tooltip, in milliseconds90 91        Note that a widget will only be shown when showtip() is called,92        e.g. after hovering over the anchor widget with the mouse for enough93        time.94        """95        super().__init__(anchor_widget)96        self.hover_delay = hover_delay97 98        self._after_id = None99        self._id1 = self.anchor_widget.bind("<Enter>", self._show_event)100        self._id2 = self.anchor_widget.bind("<Leave>", self._hide_event)101        self._id3 = self.anchor_widget.bind("<Button>", self._hide_event)102 103    def __del__(self):104        try:105            self.anchor_widget.unbind("<Enter>", self._id1)106            self.anchor_widget.unbind("<Leave>", self._id2)  # pragma: no cover107            self.anchor_widget.unbind("<Button>", self._id3) # pragma: no cover108        except TclError:109            pass110        super().__del__()111 112    def _show_event(self, event=None):113        """event handler to display the tooltip"""114        if self.hover_delay:115            self.schedule()116        else:117            self.showtip()118 119    def _hide_event(self, event=None):120        """event handler to hide the tooltip"""121        self.hidetip()122 123    def schedule(self):124        """schedule the future display of the tooltip"""125        self.unschedule()126        self._after_id = self.anchor_widget.after(self.hover_delay,127                                                  self.showtip)128 129    def unschedule(self):130        """cancel the future display of the tooltip"""131        after_id = self._after_id132        self._after_id = None133        if after_id:134            self.anchor_widget.after_cancel(after_id)135 136    def hidetip(self):137        """hide the tooltip"""138        try:139            self.unschedule()140        except TclError:  # pragma: no cover141            pass142        super().hidetip()143 144 145class Hovertip(OnHoverTooltipBase):146    "A tooltip that pops up when a mouse hovers over an anchor widget."147    def __init__(self, anchor_widget, text, hover_delay=1000,148                 foreground="#000000", background="#ffffe0"):149        """Create a text tooltip with a mouse hover delay.150 151        anchor_widget: the widget next to which the tooltip will be shown152        hover_delay: time to delay before showing the tooltip, in milliseconds153 154        Note that a widget will only be shown when showtip() is called,155        e.g. after hovering over the anchor widget with the mouse for enough156        time.157        """158        super().__init__(anchor_widget, hover_delay=hover_delay)159        self.text = text160        self.foreground = foreground161        self.background = background162 163    def showcontents(self):164        label = Label(self.tipwindow, text=self.text, justify=LEFT,165                       relief=SOLID,  borderwidth=1,166                       foreground=self.foreground, background=self.background)167        label.pack()168 169 170def _tooltip(parent):  # htest #171    top = Toplevel(parent)172    top.title("Test tooltip")173    x, y = map(int, parent.geometry().split('+')[1:])174    top.geometry("+%d+%d" % (x, y + 150))175    label = Label(top, text="Place your mouse over buttons")176    label.pack()177    button1 = Button(top, text="Button 1 -- 1/2 second hover delay")178    button1.pack()179    Hovertip(button1, "This is tooltip text for button1.", hover_delay=500)180    button2 = Button(top, text="Button 2 -- no hover delay")181    button2.pack()182    Hovertip(button2, "This is tooltip\ntext for button2.", hover_delay=None)183 184 185if __name__ == '__main__':186    from unittest import main187    main('idlelib.idle_test.test_tooltip', verbosity=2, exit=False)188 189    from idlelib.idle_test.htest import run190    run(_tooltip)191 
codekingpro/portable-devtools · Team Ai