DropDown list: How to open by default?

29 views
Skip to first unread message

Henrik R.

unread,
Jun 24, 2024, 4:23:35 PM (8 days ago) Jun 24
to Kivy users support
Hi!
I want to include a DropDown list in my Kivy app, but I want the list of choices to be open (displayed) by default, so the user does not have to press the 'main button', to see the list. 
I cannot see how to do that?
I tried:
dropdown = MyDropDown(is_open=True)
And:
# create a big main button:
dropdown_headline = ScalableButton(text="Choose target from the list") # , size_hint=(None, None)
dropdown_headline.bind(dropdown.open) # was on_release=dropdown.open
None of that worked...

ElliotG

unread,
Jun 24, 2024, 6:42:33 PM (8 days ago) Jun 24
to Kivy users support
Here is an example that creates a DropDown(), and shows it in the open state.

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.metrics import dp
from kivy.clock import Clock


kv = """
AnchorLayout:
    anchor_y: 'top'
    ButtonDropDown:
        text: 'Big Button Drop Down'
        size_hint: None, None
        size: dp(300), dp(100)
"""

class ButtonDropDown(Button):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.dropdown = DropDown()
        Clock.schedule_once(self.add_buttons)

    def add_buttons(self, _):
        for i in range(10):
            button = Button(text=f'Item {i}', size_hint_y=None, height=dp(48))
            button.bind(on_release=lambda btn: self.dropdown.select(btn.text))
            self.dropdown.add_widget(button)
        self.bind(on_release=self.dropdown.open)
        self.dropdown.bind(on_select=lambda instance, x: setattr(self, 'text', x))
        self.dropdown.open(self)  # open the dropdown


class DDApp(App):
    def build(self):
        return Builder.load_string(kv)


DDApp().run()

Henrik R.

unread,
Jun 26, 2024, 10:11:22 AM (7 days ago) Jun 26
to Kivy users support
Great. Thank you! That code works. :-)

But why do you have to:
    Clock.schedule_once(self.add_buttons)
And why do you NOT:
    self.add_widget(self. dropdown)

ElliotG

unread,
Jun 26, 2024, 12:00:20 PM (6 days ago) Jun 26
to Kivy users support
I added the clock because the Button was not rendering, so I added to clock to see if that was needed - and it worked.
I did not add do a self.add_widget(self.dropdown)... I followed the example in the docs.
Message has been deleted

Henrik R.

unread,
Jun 28, 2024, 7:39:14 AM (5 days ago) Jun 28
to Kivy users support
OK. :-) Your code works fine as a standalone. But when I insert it in my app, and call it from a BoxLayout like this:

class ChooseTarget(BoxLayout):

(...)

def no_no(self):
# User will choose a target from a list
self.clear_widgets()
# I try Elliot's example that DID work as a standalone:
self.mydropdown = ButtonDropDown()

I get a strange error on the 'dropdown.open':

   File "/mnt/4AF15A0435E762B4/mypython/GeoESP/main.py", line 1612, in delayed_open

     self.dropdown.open(self)  # open the dropdown
   File "/mnt/4AF15A0435E762B4/mypython/GeoESP-android/newvenv/lib/python3.8/site-packages/kivy/uix/dropdown.py", line 246, in open
     raise DropDownException(
 kivy.uix.dropdown.DropDownException: Cannot open a dropdown list on a hidden widget

I even tried delaying 'open' using Clock (similar to your code), but that didn't change anything:

self.dropdown.bind(on_select=lambda instance, x: setattr(self, 'text', x))
Clock.schedule_once(self.delayed_open)

def delayed_open(self, _):

self.dropdown.open(self) # open the dropdown

Here is your DropDown code. I only changed height=dp(48) to height=48 in Button:

class ButtonDropDown(Button): # ScalableButton
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.dropdown = DropDown()
Clock.schedule_once(self.add_buttons)

def add_buttons(self, _):
for i in range(10):
button = Button(text=f'Item {i}', size_hint_y=None, height=48)

button.bind(on_release=lambda btn: self.dropdown.select(btn.text))
self.dropdown.add_widget(button)
self.bind(on_release=self.dropdown.open)
self.dropdown.bind(on_select=lambda instance, x: setattr(self, 'text', x))
# Clock.schedule_once(self.delayed_open)

# def delayed_open(self, _):
self.dropdown.open(self) # open the dropdown

Do you have any idea about what goes wrong?

Love,
Henrik

PS: I am away on holiday for a week, starting tomorrow (Saturday).

ElliotG

unread,
Jun 28, 2024, 11:17:18 AM (5 days ago) Jun 28
to Kivy users support
Enjoy your holiday!
When you have a chance, send an executable program that demonstrates the issue.  I've extended the previous example:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.metrics import dp
from kivy.properties import ListProperty

from kivy.clock import Clock


kv = """
AnchorLayout:
    anchor_y: 'top'
    BoxLayout:
        size_hint_y: None
        height: self.minimum_height
        ButtonDropDown:
            text: 'Big Drop Down 1'
            size_hint: None, None
            size: dp(150), dp(100)
            values: ['A', 'B', 'C']
        ButtonDropDown:
            text: 'Big Drop Down 2'
            size_hint: None, None
            size: dp(200), dp(100)
            values: [str(x) for x in range(10)]
        ButtonDropDown:
            text: 'Big Drop Down 3'
            size_hint: None, None
            size: dp(250), dp(100)
            values: [str(x) for x in range(10, 20)]
        ButtonDropDown:
            text: 'Big Drop Down 4'
            size_hint: None, None
            size: dp(150), dp(100)
            values: ['Red', 'Yellow', 'Orange', 'Green']
       
"""

class ButtonDropDown(Button):
    values = ListProperty()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.dropdown = DropDown(auto_dismiss=False)
        Clock.schedule_once(self.add_buttons)


    def add_buttons(self, _):
        for i in self.values:
            button = Button(text=f'Item {i}', size_hint_y=None, height=dp(48))

            button.bind(on_release=lambda btn: self.dropdown.select(btn.text))
            self.dropdown.add_widget(button)
        self.bind(on_release=self.dropdown.open)
        self.dropdown.bind(on_select=lambda instance, x: setattr(self, 'text', x))
        self.dropdown.open(self)  # open the dropdown


class DDApp(App):
    def build(self):
        return Builder.load_string(kv)


DDApp().run()
drop_down.py
Reply all
Reply to author
Forward
0 new messages