Search code examples
pythonbindingkivydropdown

Dropdown menu not working using Kivy Language


I am trying to make a simple dropdown menu using only Kivy Language.

This program is a simple image that the user can resize, with a button that brings up a dropdown menu. When the program starts, part of the dropdown menu is appearing near the bottom. Other than that, everything looks right. When clicked, nothing happens, except the part of the dropdown menu that's visible (that I didn't want visible yet) disappears.

# .py file
import kivy 
from kivy.app import App 
# kivy.require('1.9.0') 

from kivy.uix.scatter import Scatter 
from kivy.uix.widget import Widget 
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button

# Creating widget class 
class SquareWidget(Widget):
    pass
# Creating Scatter Class 
class ScatterWidget(Scatter):
    do_rotation=False

# Create the layout class 
class Scatter_App(RelativeLayout):
    pass

class ScatterApp(App): 
    def build(self):
        return Scatter_App()

if __name__=='__main__': 
    ScatterApp().run()
# .kv file
# Create the scatter properties        
<SquareWidget>:
    size: self.parent.size
    canvas:
        Rectangle:
            size: self.size 
            pos: self.pos
            source: 'image.jpg'  

<Scatter_App>:
    canvas: 
        Rectangle: 
            size: self.size 
            pos: self.pos 

    ScatterWidget: 
        id: square_widget_id 
        SquareWidget:

    DropDown:
        id: cdd
        Button:
            text: 'Item 1'
        Label:
            text: 'Item 2'
        Label:
            text: 'Item 3'

    Button:
        background_normal: ''
        background_color: 1, .2, .3, .85
        text: 'Choose'
        text_size: self.size
        text_pos: self.height/2,self.width/2
        size_hint: .15,.15
        pos: (self.parent.width-self.width)/2,self.parent.height-self.height
        on_release: cdd.open

Solution

  • A few problems:

    • If you add a DropDown directly in kv, it will become a child of Scatter_App, just like any other Widget. Then, trying to call open() on it will fail, because open() tries to do an add_widget (but the DropDown already has a parent).
    • Your rule for the DropDown does not specify the height of each of the added Widgets. From the documentation:

    When adding widgets, we need to specify the height manually

    • When calling open() on a DropDown, you must include an argument that specifies the Widget that the DropDown should attach to.

    So, taking all this into account, I have created a slightly modified version of your kv file:

    # .kv file
    # Create the scatter properties     
    #:import Factory kivy.factory.Factory
    <SquareWidget>:
        size: self.parent.size
        canvas:
            Rectangle:
                size: self.size 
                pos: self.pos
                source: 'image.jpg'  
    
    # add a dynamic class that extends DropDown
    <MyDropDown@DropDown>:
        Button:
            text: 'Item 1'
            size_hint_y: None
            height: 40
        Label:
            text: 'Item 2'
            size_hint_y: None
            height: 40
        Label:
            text: 'Item 3'
            size_hint_y: None
            height: 40
    
    <Scatter_App>:
        canvas: 
            Rectangle: 
                size: self.size 
                pos: self.pos 
    
        ScatterWidget: 
            id: square_widget_id 
            SquareWidget:
    
        Button:
            background_normal: ''
            background_color: 1, .2, .3, .85
            text: 'Choose'
            text_size: self.size
            text_pos: self.height/2,self.width/2
            size_hint: .15,.15
            pos: (self.parent.width-self.width)/2,self.parent.height-self.height
            on_release: Factory.MyDropDown().open(self)
    

    I have added a Factory import to the kv file, so that you can create the MyDropDown in the kv file. I have also added height specifications to the Widgets added to the DropDown. The MyDropDown.open() call now includes self (the Button).