Understanding __init__() and Kivy's build() methods

Viewed 40

Hello i am new to python and kivy and also new to posting on Stackoverflow, so please correct me if I use terminology incorrectly or make any other errors coding style.

I have created a GUI using kivy and python. It was everything ok till i got to the point of inserting a DropDown in the GUI. Following an example provided on the Kivy Programming guide i created a Dropdown List implementing it both in a .kv file and a python file.

The Problem is now, that the DropDown List doesn't show when i run the app. As you can see in my Python code i tried to use the method ControlsView().add_widget() to add the mainbutton to the ControlsView Layout, but with no luck.

I then tried to place it in the build() method of the app as following:


def build():
    ControlsView().add_widget(mainbutton)
    return InteractiveGUI()

but also with no luck.

The error message says:

File "logicPortable.py", line 38, in build ControlsView.add_widget(mainbutton) TypeError: add_widget() missing 1 required positional argument: 'widget'

Here's my Code:

python File:


import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.dropdown import DropDown
from kivy.lang import Builder

Builder.load_file('GUI.kv')

class InteractiveGUI(BoxLayout):
    pass

class CameraView(RelativeLayout):
    pass

class ControlsView(RelativeLayout):
    pass

class CameraDropDown(DropDown):
    pass

camera_select = CameraDropDown()
mainbutton = Button(text='Select Camera',
                    size_hint_x=.7,
                    size_hint_y=None,
                    height=35,
                    pos_hint={'center_x': .5, 'center_y': .5}
                    )
mainbutton.bind(on_release=camera_select.open)
camera_select.bind(on_select=lambda instance,x: setattr(mainbutton, 'text', x))

ControlsView().add_widget(mainbutton)

class LogPortGUI(App):
    def build(self):
        return InteractiveGUI()

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

kv File:


#:import Factory kivy.factory.Factory

<PopupStart@Popup>:
    id : popup_start
    title: "Start Function Pop-up"
    auto_dismiss: False
    size_hint : (.4, .4)

    RelativeLayout:
        size_hint : (.8, .9)
        Button:
            text: 'Close me!'
            size_hint : (.45, .25)
            pos_hint : {'center_x':0.5, 'y':0.1}
            on_release: root.dismiss()
        Label:
            text : "The start function will run the AI Algorithm \n and will be 
            provided soon"
            font_size : 15
            size_hint : (.55, .45)
            pos_hint : {'center_x':0.5, 'top':1}

<PopupCalibrate@Popup>:
    id : popup_calibrate
    title: "Calibrate Function Pop-up"
    auto_dismiss: False
    size_hint : (.4, .4)

    RelativeLayout:
        size_hint : (.8, .9)
        Button:
            text: 'Close me!'
            size_hint : (.45, .25)
            pos_hint : {'center_x':0.5, 'y':0.1}
            on_release: root.dismiss()
        Label:
            text : "The calibrate function will run the Camera Calibration \n and 
                    will be provided soon"
            font_size : 13
            size_hint : (.55, .45)
            pos_hint : {'center_x':0.5, 'top':1}


<CameraView>:
    playing_camera : playing_camera     #to reference in Python Code
    Camera:
        id : playing_camera
        play : True
        index : 0

    Label:
        text : "Camera n.%s" % str(playing_camera.index)
        font_size : "15sp"
        size_hint : (.3,.1)
        pos_hint : {'center_x':0.5, 'top':1}
        bold : True


<ControlsView>:

    focus_value : focus_slider.value

    Button:
        id : btn_start
        text : "Start"
        font_size : 20
        size_hint : (0.7,.1)
        pos_hint :  {'center_x':0.5, 'y':0.05}
        background_normal : ""
        background_color : (0,1,0,.5)
        bold : True
        on_release: Factory.PopupStart().open()
        #Check where the function definition should be placed
                                                       

    Button:
        id : btn_calibrate
        text : "Calibrate"
        font_size : 18
        size_hint : (0.7,.1)
        pos_hint  :  {'center_x':0.5, 'top':0.75}
        background_normal : ""
        background_color : (0, 0, 1, .5)
        on_release: Factory.PopupCalibrate().open()


    Label:
        text : "logic.portable"
        font_size : 25
        pos_hint : {'top':1.45}

    Label:
        text : "Gewicht in g"
        pos_hint : {'center_x':0.5, 'top':1.35}
        color : (1,0,0,.5)

    Label:
        text : "Focus"
        font_size : 15
        pos_hint : {'center_x': .5, 'center_y': .27}


    Slider:
        id : focus_slider
        value_track : True
        value_track_color : [1, 0, 0, 1]
        range : (20, 100)                                  
        value : 20
        step : 1
        pos_hint : {'center_x': .5, 'center_y': .25}
        size_hint_y : None
        height : 50
        on_value : root.focus_value = self.value


    Label:
        text : "Focus at %scm" % str(root.focus_value)
        font_size : 10
        pos_hint : {'center_x': .5, 'center_y': .22}


<DropDownButton@Button>:
    size_hint_x: .7
    size_hint_y: None
    height: 25


<CameraDropDown>:

    DropDownButton:
        text: 'Camera 1'
        on_release: root.select(self.text)

    DropDownButton:
        text: 'Camera 2'
        on_release: root.select(self.text)

    DropDownButton:
        text: 'Camera 3'
        on_release: root.select(self.text)

    DropDownButton:
        text: 'Camera 4'
        on_release: root.select(self.text)
   
<InteractiveGUI>:

    CameraView:
        id : cameraview
        size_hint_x : 4

    ControlsView:

My guess is that the definition of mainbutton should go inside the __init__() Method of ControlsView class.

I would like to understand WHY it doesn't work the way i'm usign it, and if someone could clarify how kivy classes and App work.

More specifically i would like to understand the following:

  • What should be written inside the build() Method of an App.

  • What should be placed inside the __init__() method of a custom class.

  • What can be placed outside of a __init__() method of a custom class.

  • Is it significant to place code outside the definition of a class when using kivy? What would the purpose be? (referred to my example where i placed "mainbutton" outside of the definition of the class)

  • In kv Language is defining a rule by <CustomClass> the same as overriding the __init()__ method of the class?

  • In kv Language is using indentation the same as using the self.add_widget() in the __init()__ Method of the class?

If someone of you could help me clarify these question or refer to a good source that covers this examples i would be very grateful.

1 Answers

The line of code:

ControlsView().add_widget(mainbutton)

is creating a new instance of ControlsView, then calling add_widget() on that instance of ControlsView, then discards that new instance of ControlsView. If you want that mainbutton to appear in your GUI, you must add that widget to the ControlsView that is in your GUI.

First, remove the offending line:

ControlsView().add_widget(mainbutton)

And add some code to actually add the mainbutton to the correct instance of ControlsView:

class ControlsView(RelativeLayout):
    def on_kv_post(self, base_widget):  # runs after the kv rules for this class have been run
        self.add_widget(mainbutton)
Related