Search code examples
pythonuser-interfacekivykivy-languagekivymd

Kivy MD: How to get the selected item from an uix.list / OneLineAvatarIconListItem


I'm quite new in Kivy. I developed a simple UI in Python/KivyMD. It displays a list of items: each of them has a checkbox that allows the user to select that item. The object that displays this list is inherited from kivymd.uix.list. I would like to get the selected item/items of this list. Here is the code:

from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.floatlayout import MDFloatLayout
from kivymd.uix.list import IRightBodyTouch, OneLineAvatarIconListItem
from kivymd.uix.selectioncontrol import MDCheckbox
from kivymd.toast import toast
import numpy as np


Builder.load_string(
    """    
<ListItemWithCheckbox>:
    RightCheckbox:
       
<View>:
    MDScrollView:
        MDList:
            id: scroll                
"""
)
    
    
class ListItemWithCheckbox(OneLineAvatarIconListItem):
    pass


class RightCheckbox(IRightBodyTouch, MDCheckbox):
    pass

    

class View(MDFloatLayout): 
    detectedDevices = list()
    for i in range(20):
        device = dict(name='DEVICE ' + str(i), index=i+1, battery_level=np.random.randint(low=0, high=101))
        detectedDevices.append(device)
    
    
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        for i in range(len(self.detectedDevices)):
            self.ids.scroll.add_widget(ListItemWithCheckbox(text=self.detectedDevices[i]['name']))
    
    
  
class MainApp(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.view = View()
        

    def build(self):
        self.title = ''
        return self.view
  

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

Solution

  • You can maintain a list of selected items by using the on_state method of MDCheckbox to trigger an update of that list whenever an item is selected.

    Here is one way to do that. First, add an id to the MDCheckBox:

    <ListItemWithCheckbox>:
        RightCheckbox:
            id: check
    

    Then modify the RightCheckbox class to run the selection update code whenever the state of any RightCheckbox changes:

    class RightCheckbox(IRightBodyTouch, MDCheckbox):
        def on_state(self, instance, new_state):
            super(RightCheckbox, self).on_state(instance, new_state)
            MDApp.get_running_app().update_selections()
    

    Then add the update_selections() method to your app:

    class MainApp(MDApp):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.selections = []  # this will hold the items selected
            self.view = View()
    
        def update_selections(self):
            # some checkbox has changed, so update the selections
            self.selections = []
            for w in self.root.ids.scroll.children:
                if w.ids.check.state == 'down':
                    self.selections.append(w.text)
            print('selected items:', self.selections)