Search code examples
python-3.xkivyiconskivymd

How do I use icons with KivyMD and Python?


I am trying to use icons with the menu_items list and I am geting nowhere. I have tried different viewclasses (OneLineListItem, OneLineAvatarIconListItem, and OneLineIconListItem) and various keys ("icon","leading_icon", "trailing_icon", "left_icon") but none of them seems to be working. With OneLineIconListItem, though, the text shifts a little to the right, like it's making space for the icon but the icon doesn't display.

Here's my code:

kv = """

Screen:

    MDIconButton:
        id: button
        icon: "dots-vertical"
        pos_hint: {"x": .2, "y": .8}
        _no_ripple_effect: True
        on_release: app.dropdown.open()

"""

class DemoApp(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.item_height = 50
        self.screen = Builder.load_string(kv)

        menu_items = [
            {
                "viewclass": "OneLineIconListItem",
                "icon": "language-python",
                "text": "Set Off",
                # one of the many attempts
                # "on_release": lambda x = f"Set {'Off' if text.endswith('On') else 'On'}!": self.callback(x),
                # another attempt at accessing "text"
                # "on_release": lambda item, message="Game Saved!": self.callback(item["text"], message),
                "height": dp(self.item_height),
                "divider": None

            }
        ]

        self.dropdown = MDDropdownMenu(
            items = menu_items, 
            width_mult = 4,
            caller = self.screen.ids.button,
            max_height = len(menu_items) * dp(self.item_height),
            )

    def build(self):

        self.theme_cls.theme_style = "Dark"
        self.theme_cls.primary_palette = "Orange"

        return self.screen

    def callback(self, *args):
        print(args[0])

        # for item in menu_items:
        #   if item['text'] == 'Set Off':
        #       print(args[0])
        #       item['text'] = 'Set On'
        #   elif item['text'] == 'Set On':
        #       print(args[0])
        #       item['text'] = 'Set Off'
        #   else:
        #       print(args[0])

DemoApp().run()

Also, please note that I'm trying to access and update the "text" key with no success. If I press on the dropdown item, I want to change its text from, say, 'Set Off' to 'Set On' and vice-versa.

Any assistance will be highly appreciated. Thanks.


Solution

  • You cannot use the icon attribute directly in the OneLineIconListItem. The example in the documentation shows:

    OneLineIconListItem:
        text: "Single-line item with avatar"
    
        IconLeftWidget:
            icon: "language-python"
    

    So the icon must be used as an attribute of a subordinate IconLeftWidget. A work around is to create your own custom version of the OneLineIconListItem, perhaps named MyOneLineIconListItem:

    class MyOneLineIconListItem(OneLineIconListItem):
        icon = StringProperty('')  # property to handle the icon
    

    Then in your kv you can include a rule for the new class:

    <MyOneLineIconListItem>:
        IconLeftWidget:
            icon: root.icon
    

    Then just use MyOneLineIconListItem as the viewclass in the menu items:

    "viewclass": "MyOneLineIconListItem",