Skip to content Skip to sidebar Skip to footer

How To Make Tooltip Using Kivy?

I want to see tooltip as in Qt when the mouse pointer is hovering over icon in ActionBar. Yes, I can use mode='spinner', but icons are nicer.

Solution 1:

A simple example you can improve and extend:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.actionbar import ActionButton
from kivy.uix.label import Label
from kivy.clock import Clock

Builder.load_string("""
<Tooltip>:
    size_hint: None, None
    size: self.texture_size[0]+5, self.texture_size[1]+5
    canvas.before:
        Color:
            rgb: 0.2, 0.2, 0.2
        Rectangle:
            size: self.size
            pos: self.pos

<MyWidget>
    ActionBar:
        ActionView:
            MyActionButton:
                icon: 'atlas://data/images/defaulttheme/audio-volume-high'
            MyActionButton:
                icon: 'atlas://data/images/defaulttheme/audio-volume-high'                
""")

classTooltip(Label):
    passclassMyActionButton(ActionButton):
    tooltip = Tooltip(text='Hello world')

    def__init__(self, **kwargs):
        Window.bind(mouse_pos=self.on_mouse_pos)
        super(ActionButton, self).__init__(**kwargs)

    defon_mouse_pos(self, *args):
        ifnot self.get_root_window():
            return
        pos = args[1]
        self.tooltip.pos = pos
        Clock.unschedule(self.display_tooltip) # cancel scheduled event since I moved the cursor
        self.close_tooltip() # close if it's openedif self.collide_point(*self.to_widget(*pos)):
            Clock.schedule_once(self.display_tooltip, 1)

    defclose_tooltip(self, *args):
        Window.remove_widget(self.tooltip)

    defdisplay_tooltip(self, *args):
        Window.add_widget(self.tooltip)


classMyWidget(Widget):
    passclassClientApp(App):
    defbuild(self):
        return MyWidget()

if __name__ == '__main__':
    ClientApp().run()

First I bind on_mouse_pos method to Window.mouse_pos event so I can detect when the mouse cursor hovers over my subclass of ActionButton. This is based on this snippet. Then I shedule an action with Clock.schedule_once() to make my toolbox visible if I won't move my cursor. To display I'm just adding a subclass of Label to the stack of widgets. You can replace display_tooltip() and close_tooltip() methods with more sophisticated ones.


EDIT: Updated the code accordingly to this answer

Solution 2:

Extended Spinner with Tooltip

OK, I have extend it a little bit. Now it's possible to set tooltip text in KV language. So every object/instance would have its own tooltip. Tooltip and its text tooltip_txt, are properties of the ToolTipSpinner.

from kivy.app import App
from kivy.core.window import Window
Window.minimum_width, Window.minimum_height = 800, 600from kivy.clock import Clock
from kivy.compat import string_types
from kivy.uix.spinner import Spinner
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.properties import ObjectProperty
from kivy.factory import Factory
from kivy.lang import Builder

Builder.load_string("""
<ToolTipSpinner>:
<Tooltip>:
    size_hint: None, None
    size: self.texture_size[0]+5, self.texture_size[1]+5
    canvas.before:
        Color:
            rgb: 0.2, 0.2, 0.2
        Rectangle:
            size: self.size
            pos: self.pos

<MyBar>:
    orientation: 'horizontal'
    padding: 2
    spacing: 2
    canvas.before:
        Color:
            rgba: 1, 1, 1, 1
        Line:
            width: 1.
            rectangle: (self.x+1, self.y-1, self.width, self.height)
    BoxLayout:
        orientation: 'horizontal'
        padding: 2,2,2,2
        spacing: 2
        size_hint: None, 1
        width: 110
        ToolTipSpinner:
            id:  _spinner_type_1
            tooltip_txt: 'Tooltip T1'
            text:  'Type 1'
            values:   ['0', '1', '2', '3']
            size_hint:  None, .45
            on_text:  self.on_spinner_select(self.text)
        ToolTipSpinner:
            id:  _spinner_type_2
            tooltip_txt: 'Tooltip T2\\nwith newline'
            text:  'Type 2'
            values:   ['4', '5', '6', '7', '8', '9']
            size_hint:  None, .45
            on_text:  self.on_spinner_select(self.text)
""")


classTooltip(Label):
    passclassMyBar(BoxLayout):
    passclassToolTipSpinner(Spinner):
    tooltip_txt = StringProperty('')
    tooltip_cls = ObjectProperty(Tooltip)
    
    def__init__(self, **kwargs):
        self._tooltip = Nonesuper(ToolTipSpinner, self).__init__(**kwargs)
        fbind = self.fbind
        fbind('tooltip_cls', self._build_tooltip)
        fbind('tooltip_txt', self._update_tooltip)
        Window.bind(mouse_pos=self.on_mouse_pos)
        self._build_tooltip()
    
    def_build_tooltip(self, *largs):
        if self._tooltip:
            self._tooltip = None
        cls = self.tooltip_cls
        ifisinstance(cls, string_types):
            cls = Factory.get(cls)
        self._tooltip = cls()
        self._update_tooltip()
    
    def_update_tooltip(self, *largs):
        txt = self.tooltip_txt
        if txt:
            self._tooltip.text = txt
        else:
            self._tooltip.text = ''defon_spinner_select(self, text):
        print(text)
    
    defon_mouse_pos(self, *args):
        ifnot self.get_root_window():
            return
        pos = args[1]
        self._tooltip.pos = pos
        Clock.unschedule(self.display_tooltip) # cancel scheduled event since I moved the cursor
        self.close_tooltip() # close if it's openedif self.collide_point(*self.to_widget(*pos)):
            Clock.schedule_once(self.display_tooltip, 1)

    defclose_tooltip(self, *args):
        Window.remove_widget(self._tooltip)

    defdisplay_tooltip(self, *args):
        Window.add_widget(self._tooltip)
        
        
classMainApp(App):
    defbuild(self):
        return MyBar()

if __name__ == '__main__':
    MainApp().run()

Post a Comment for "How To Make Tooltip Using Kivy?"