10

This is very related to this other question. The only difference is that I am adding the Ellipse dynamically with with self.canvas instead of using the Builder (Builder.load_string or Builder.load_file). So here is the code that does work. When you click in the Ellipse it moves and change Color:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty
from kivy.graphics import Color, Ellipse

Builder.load_string("""
<CircleWidget>:
    canvas:
        Color:
            rgba: self.r,1,1,1
        Ellipse:
            pos: self.pos
            size: self.size
""")

class CircleWidget(Widget):
    r = NumericProperty(0)
    def __init__(s, **kwargs):
        s.size= [50,50]
        s.pos = [100,50]
        super(CircleWidget, s).__init__(**kwargs)

    def on_touch_down(s, touch):
        if s.collide_point(touch.x,touch.y):    
            s.pos = [s.pos[1],s.pos[0]]     # this works
            s.r = 1.0                       # this also works

class TestApp(App):
    def build(s):
        parent = Widget()
        parent.add_widget(CircleWidget())
        return parent

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

If I try to do the same without using the Builder, it doesn't work anymore:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty
from kivy.graphics import Color, Ellipse

class CircleWidget(Widget):
    r = NumericProperty(0)
    def __init__(s, **kwargs):
        s.size= [50,50]
        s.pos = [100,50]
        super(CircleWidget, s).__init__(**kwargs)
        with s.canvas:
            Color(s.r,1,1,1)
            Ellipse(pos = s.pos, size = s.size)

    def on_touch_down(s, touch):
        if s.collide_point(touch.x,touch.y):    
            s.pos = [s.pos[1],s.pos[0]]     # This doesn't work anymore
            s.r = 1.0                       # Neither do this

class TestApp(App):
    def build(s):
        parent = Widget()
        parent.add_widget(CircleWidget())
        return parent

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

The code runs and the event is actually called. More over, the Widget is moved (even if it is visually not clear) but the Instructions of the canvas are not updated.

Any ideas?

Community
  • 1
  • 1
toto_tico
  • 17,977
  • 9
  • 97
  • 116

1 Answers1

10

The first version works because kv lang automatically bind the canvas recreation to properties in expressions, so these lines:

    Color:
        rgba: self.r,1,1,1

do more than this one:

    Color(s.r,1,1,1)

what you can do, howether, is to bind self.r to auto rebuild your canvas instructions.

in __init__

self.bind(r=self.redraw)
self.bind(pos=self.redraw)
self.bind(size=self.redraw)

and move the

    with s.canvas:
        Color(s.r,1,1,1)
        Ellipse(pos = s.pos, size = s.size)

Part to a method named redraw, with a self.canvas.clear() call before.

full result:

from kivy.app import App
from kivy.uix.widget import Widget

from kivy.properties import NumericProperty
from kivy.graphics import Color, Ellipse

class CircleWidget(Widget):
    r = NumericProperty(0)

    def __init__(s, **kwargs):
        super(CircleWidget, s).__init__(**kwargs)
        s.bind(r=s.redraw)
        s.bind(pos=s.redraw)
        s.bind(size=s.redraw)
        s.size = [50, 50]
        s.pos = [100, 50]

    def redraw(s, *args):
        s.canvas.clear()
        with s.canvas:
            Color(s.r, 1, 1, 1)
            Ellipse(pos = s.pos, size = s.size)

    def on_touch_down(s, touch):
        if s.collide_point(touch.x, touch.y):
            print "gotcha"
            s.pos = [s.pos[1], s.pos[0]]
            s.r = 1.0

class TestApp(App):
    def build(s):
        parent = Widget()
        parent.add_widget(CircleWidget())
        return parent

if __name__ == '__main__':
    TestApp().run()
Tshirtman
  • 5,859
  • 1
  • 19
  • 26
  • Thank you very much! I was starting to suspect that the Builder was doing something else than just parsing the Kivy language. – toto_tico Jun 17 '13 at 08:15
  • 2
    Well, technically it's part of the parsing, it's just that the kv language is built to make these things easier than plain python. Thanks for the bonus :). – Tshirtman Jun 17 '13 at 09:32