Search code examples
pythonkivydropdown

Kivy DropDown Lists using Iteration


I'm trying to generate multiple dropdown lists that each have the same data in it, but will be used as different variables. Currently my code will generate all of the dropdown lists. Although every time I try to change a value in any of the dropdown lists the value will be assigned to the very last dropdown list instead of where it was opened from.

I started off with not using any lists and then the code worked properly, but it was just very inefficient. Thus, I wanted to cut the repetitive parts down and form some lists instead. I've played around with different "lambda" statements and believe that the fault lies in btn[i].bind(on_release=lambda btn=btn[i]: dropdown[i].select(btn.text)) line of code (I can be totally wrong). I'm not sure if I'm setting up any of the lambda functions correctly with the code I've written.

first_row is a list of data from an Excel File. default_list is a list of random strings

dropdown = [DropDown() for x in range (len(default_list))]
btn = [Button() for x in range (len(default_list))]
main_btn = [Button() for x in range (len(default_list))]
col_found = GridLayout(cols = 1)
## create buttons for dropdown lists with excel data
for index in range(0, len(first_row)):
     for i in range (0, len(default_list)):
         btn[i] = Button(text=str(first_row[index])+'%d'%i,  size_hint_y=None, height=24, color = (1,1,1,1))
         btn[i].bind(on_release=lambda btn=btn[i]: dropdown[i].select(btn.text))
         dropdown[i].add_widget(btn[i])

## set up main buttons with dropdown lists and add them to the pop up                        
for i in range (0, len(default_list)):
     main_btn[i] = Button(text = "default%d"%i, on_release=dropdown[i].open, color = (1,1,1,1))
     dropdown[i].bind(on_select=lambda instance, x=dropdown[i]: setattr(main_btn[i], 'text', x))
     col_found.add_widget(main_btn[i])
                        

Expected: When selecting a value from any of the dropdowns, it should assign it to the corresponding "button"

Actual Results: When selecting a value from any of the dropdowns, value is assigned to the very last button. See these images for a better illustration:

All Dropdown Lists

All Dropdown Lists

Assigned to wrong place

Assigned to wrong place


Solution

  • The solution is create the main buttons and bind its on_release event to create, populate, and open the DropDown list.

    main.py

    from kivy.base import runTouchApp
    from kivy.uix.dropdown import DropDown
    from kivy.uix.button import Button
    from kivy.uix.gridlayout import GridLayout
    
    default_list = ['Python', 'Kivy', 'Tkinter']
    first_row = ['abc', 'def', 'ghi', 'jkl']
    
    
    col_found = GridLayout(cols=1)
    
    
    def show_dropdown(button, *largs):
        dp = DropDown()
        dp.bind(on_select=lambda instance, x: setattr(button, 'text', x))
    
        for i in range(len(first_row)):
            item = Button(text=str(first_row[i]) + '%d' % i, size_hint_y=None, height=24, color=(1, 1, 1, 1))
            item.bind(on_release=lambda btn: dp.select(btn.text))
            dp.add_widget(item)
        dp.open(button)
    
    
    for i in range(len(default_list)):
        btn = Button(text=default_list[i], color=(1, 1, 1, 1), size_hint=(None, None))
        btn.bind(on_release=show_dropdown)
        col_found.add_widget(btn)
    
    
    runTouchApp(col_found)
    

    Output

    App Startup Clicked Kivy Button Kivy text replaced with text from selected dropdown list