how to use drop down widget in kivy with a python class

bosky picture bosky · Jan 22, 2014 · Viewed 12.3k times · Source

So, I think there should be at least two ways that I could have a drop down menu on this page, but I can get neither to work. I am new to kivy and programming in general, but I have read the documentation and it seems that I simply do not understand.

I have created the following example:

import kivy
kivy.require('1.7.2') # replace with your current kivy version !

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.button import Button
from kivy.uix.dropdown import DropDown

class CustomDropDown(DropDown):
    pass

class HomeScreen(Screen):
    translateInput = ObjectProperty(None)
    translateButton = ObjectProperty(None)
    translateLabel = ObjectProperty(None)
    top_layout = ObjectProperty(None)
    dd_btn = ObjectProperty(None)
    drop_down = CustomDropDown()
    #notes_dropdown = ObjectProperty(None)


    dropdown = DropDown()
    notes = ['Features', 'Suggestions', 'Abreviations', 'Miscellaneous']
    for note in notes:
        # when adding widgets, we need to specify the height manually (disabling
        # the size_hint_y) so the dropdown can calculate the area it needs.
        btn = Button(text='%r' % note, size_hint_y=None, height=30)

        # for each button, attach a callback that will call the select() method
        # on the dropdown. We'll pass the text of the button as the data of the
        # selection.
        btn.bind(on_release=lambda btn: dropdown.select(btn.text))

        # then add the button inside the dropdown
        dropdown.add_widget(btn)

    # create a big main button
    mainbutton = Button(text='Usage Notes 2', size_hint=(1, 1))

    # show the dropdown menu when the main button is released
    # note: all the bind() calls pass the instance of the caller (here, the
    # mainbutton instance) as the first argument of the callback (here,
    # dropdown.open.).
    mainbutton.bind(on_release=dropdown.open)
    #dd_btn.bind(on_release=dropdown.open)

    # one last thing, listen for the selection in the dropdown list and
    # assign the data to the button text.
    dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
    #dropdown.bind(on_select=lambda instance, x: setattr(dd_btn, 'text', x))

    #top_layout.add_widget(mainbutton)


class dropdApp(App):

    def build(self):

        return HomeScreen()



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

And this is the corresponding .kv file:

#:kivy 1.7.2

<CustomDropDown>:
    Button:
        text: 'My first Item'
        size_hint_y: None
        height: 44
        on_release: root.select('item1')
    Label:
        text: 'Unselectable item'
        size_hint_y: None
        height: 44
    Button:
        text: 'My second Item'
        size_hint_y: None
        height: 44
        on_release: root.select('item2')

<HomeScreen>:
    id: home_screen
    translateInput: translateInputID
    translateButton: translateButtonID
    translateLabel: labelID
    top_layout: topLayoutID
    #notes_dropdown: notesDropDownID
    dd_btn: btn_ddID

    orientation: 'vertical'
    FloatLayout:
        size_hint: 1, .95
        TextInput:
            id: translateInputID
            text: 'cove'
            #text: 'ﻰﺸَﻣ'
            font_name: "data/fonts/DejaVuSans.ttf"
            background_color: 1, 1, 1, 1
            size_hint: .75, .1
            multiline: False
            pos_hint: {'x': .125, 'y': .45}
            text_size: self.size
            valign: 'middle'
            halign: 'center'
            padding: 5

        Button:
            id: translateButtonID
            text: 'Translate'
            pos_hint: {'x': .35, 'y': .35}
            size_hint: .3, .08
            valign: 'middle'
            halign: 'center'
            text_size: self.size
            on_release: root.translateButtonPressed()
            #on_press: root.manager.current = 'resultsscreen'

        Label:
            id: labelID
            text: 'Translator'
            text_size: self.size
            valign: 'middle'
            halign: 'center'
            pos_hint: {'x': .3, 'y': .75}
            size_hint: .4, .2
            #font_name: "simpo.ttf"
            #font_name: "5thgradecursive.ttf"
            #font_name: "AGA-Rasheeq-Regular.ttf"
            font_name: "data/fonts/DejaVuSans.ttf"
            font_size: 50

    BoxLayout:
        id: topLayoutID
        #cols: 2
        size_hint: 1, .05
        pos_hint: {'x': 0, 'y': .95}
        Button:
            #id: notesDropDownID 
            id: btn_ddID
            text: 'Usage Notes'
            on_release: root.drop_down.open
        Button:
            text: 'About'
  1. The first drop-down menu should be attached to the already created button, "Usage Notes", at the bottom of the kv file. It is attached to the class in python, "CustomDropDown", and the corresponding in the kv file. You might notice this example is straight out of the kivy documentation. I thought by creating the line:

    drop_down = CustomDropDown()
    

    it gave me a handle in both python and the kivy side to manipulate it, but as you might notice when you run it and click "Usage Notes", nothing happens.

  2. The second drop-down menu is created in python also following the kivy documentation. I would think it would create a third button at the top of the app, titled, "Usage Notes 2". I just get an error when I try to add it. Right now the line (53 on my file):

    top_layout.add_widget(mainbutton)
    

    is commented out or the app wouldn't even run, raising the error:

    AttributeError: 'kivy.properties.ObjectProperty' object has no attribute 'add_widget'
    

    Which I realize that I did set

    top_layout = ObjectProperty(None)
    

    but that is what kivy suggests doing for many widgets, and I have done with many others without this error.

I'm sure one or both of these issues is simple to someone out there. What am I missing?

Answer

FistFullOfNoodles picture FistFullOfNoodles · Jun 8, 2017

I'm posting this here in the hope that it helps other kivy beginners who just want a dropdown button that they can place in a .kv file.

class DropBut(Button):
    def __init__(self, **kwargs):
        super(DropBut, self).__init__(**kwargs)
        self.drop_list = None
        self.drop_list = DropDown()

        types = ['Item1', 'Item2', 'Item3', 'Item4', 'Item5', 'Item6']

        for i in types:
            btn = Button(text=i, size_hint_y=None, height=50)
            btn.bind(on_release=lambda btn: self.drop_list.select(btn.text))
           
            self.drop_list.add_widget(btn)

        self.bind(on_release=self.drop_list.open)
        self.drop_list.bind(on_select=lambda instance, x: setattr(self, 'text', x))