Search code examples
python-2.7kivykivy-language

Kivy - Addressing An Ellipse Widget Created In KV Language Using Python


I'd like to control a simple Ellipse widget created in Kivy using KV Language. I have been working on this for days having read and worked through the exercises in the book Kivy: Interactive Applications in Python by Roberto Ulloa and Ben Rousch's online workshop at https://bradfortner.wordpress.com/2017/07/19/good-kivy-tutorial/.

While the examples provided in those tutorials seem to work fine on pre-defined Kivy widgets (ie. Buttons and Labels) I'm having trouble controlling Widgets that I define such as a circular ellipse as shown in the code below.

In the code (below) I create the circular ellipse class Widget (named Ball) on lines 10 and 45. I place the Ball Widget on my layout (line 29) and then id the Widget as my_circle (line 30). Finally I provide the code to link the widget to Python (line 26) so Python code can control the Widget.

However when I press the "Shrink Circle" button and the shrink_circle() function is called there is no effect on the widget. Any idea where the code goes wrong? I'd love to know because it's become quite the mystery to me and I cant find anything simple that explains what I need to do to correct this.

Full code below.

Appreciated in advance.

....brad....

# Modified from https://github.com/brousch/pyohio-kivy-tutorial/blob/master/tutorial/step11_tts/saythis.kv

import kivy
from kivy.lang import Builder
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
kivy.require("1.9.1")

Builder.load_string('''
<Ball>:
    size: 1, 1
    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Ellipse:
            pos: 350,290
            size: 70,70
<ShrinkThis>:
    button_font_size: '30sp'
    canvas:
        Color:
            rgba: 0, 0, 0, 1
        Rectangle:        
            pos: self.pos
            size: self.size
    my_circle: my_circle
    BoxLayout:
        orientation: 'horizontal'
        Ball:
            id: my_circle
        Button:
            text: 'Shrink Circle'
            font_size: root.button_font_size
            size_hint: 1, None
            on_press: root.shrink_circle()            
''')

class ShrinkThis(BoxLayout):

    my_circle = ObjectProperty(None)

    def shrink_circle(self):
        self.my_circle.size = (10,10)

class Ball(Widget):
    pass

class ShrinkThisApp(App):
    def build(self):
        return ShrinkThis()

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

Solution

  • Remember that kivy canvas is not a widget and it isn't the space in which you paint, it is just a set of instructions to draw. Ball should be a widget.

    On the other hand, the size property is ignored if size_hint property is not disabled.

    Simplified example:

    import kivy
    kivy.require("1.9.1")
    
    from kivy.app import App
    from kivy.lang import Builder
    from kivy.properties import ObjectProperty
    from kivy.uix.floatlayout import FloatLayout
    
    
    Builder.load_string('''
    <Ball@Widget>
        size: 70, 70
        pos: 350,290
        size_hint: None, None
    
        canvas:
            Color:
                rgba: 1, 1, 1, 1
            Ellipse:
                pos: self.pos
                size: self.size
    
    <ShrinkThis>:
        button_font_size: '30sp'
        my_circle: my_circle
    
        Ball:
            id: my_circle
        Button:
            text: 'Shrink Circle'
            font_size: root.button_font_size
            size_hint: 1, None
            on_press: root.shrink_circle()            
    ''')
    

    Output:

    enter code here