My goal is a drop down list similar to those seen in Windows File Explorer:
I'm experimenting with DropDown
with the following code:
main.py
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.textinput import TextInput
from kivy.properties import ObjectProperty
class CustomDropDown(TextInput):
droplist = ObjectProperty(None)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.droplist.open(self)
return super().on_touch_down(touch)
class MainApp(AnchorLayout):
pass
class MyApp(App):
def build(self):
return MainApp()
if __name__ == '__main__':
MyApp().run()
my.kv
<MainApp>:
CustomDropDown:
<CustomDropDown>
text: 'Select an option..'
size_hint_y: None
height: 30
droplist: options
DropDown:
id: options
Label:
text: 'Option 1'
Label:
text: 'Option 2'
Label:
text: 'Option 3'
I get the following error on the line self.droplist.open(self)
:
Cannot add <kivy.uix.dropdown.DropDown object at 0x00000223791F39E0> to window, it already has a parent <__main__.CustomDropDown object at 0x00000223791BA580>
I think this should be working, and after some time troubleshooting I still can't figure out why it doesn't. Does anyone spot my error?
--UPDATE 9/12/2021 3:30PM--
Thank you @inclement for the suggestion, thanks to your response I was able to move forward. However, I now have a follow-up question:
To implement the suggestion, I sub-classed DropDown
and Label
and overrode the on_select
and on_touch_down
methods, respectively. I also had to override the __init__
method of DropDown
in my subclass, so that I could get access to the TextInput
box and update its content on with on_select
. This seems awkward and adds a lot of code, am I missing something that would cut down on the amount and complexity of this sort of code?
updated main.py
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
class CustomDropDown(TextInput):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.dropdown = DropDownList(self)
for item in ['Option 1', 'Option 2', 'Option 3']:
lbl = DropDownItem(text=item, size_hint_y=None, height=30)
self.dropdown.add_widget(lbl)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.dropdown.open(self)
return super().on_touch_down(touch)
class DropDownList(DropDown):
def __init__(self, user_choice, **kwargs):
super().__init__(**kwargs)
self.user_choice = user_choice
def on_select(self, data):
setattr(self.user_choice, 'text', data)
class DropDownItem(Label):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
dropdown = self.parent.parent
dropdown.select(self.text)
return super().on_touch_down(touch)
class MainApp(AnchorLayout):
pass
class MyApp(App):
def build(self):
return MainApp()
if __name__ == '__main__':
MyApp().run()
Updated my.kv
<MainApp>:
DropDownTextInput:
<DropDownTextInput>
text: 'Select an option..'
size_hint_y: None
height: 30
Thanks again!