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:
The solution is create the main buttons and bind its on_release
event to create, populate, and open the DropDown
list.
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)