SU_Medicat
SU_Medicat

Reputation: 41

Kivy: Draw circle to middle of screen on startup

I am building an app using Kivy and would like to draw a circle to the middle of a Widget as soon as the app starts up. I found how to run code on start in this question (How do I run a function once the form is loaded Kivy). However, as a comment points out, widths and heights are not initialized yet when calling on_start(). Does anyone know how I could do this?

I have the following code. Using this, the circle is drawn at position 50, 50, while I would like it in the middle of the Field widget.

main.py:

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

class Field(Widget):
    def __init__(self, **kwargs):
        super(Field, self).__init__(**kwargs)

    def init_circle(self):
        with self.canvas:
            Color(1,1,1,1, mode='rgba')
            r = 20
            self.circle = Ellipse(pos=(self.width//2 - r, self.height//2 - r), size=(2*r, 2*r))
            print(self.circle)

    def move_circle(self):
        cx, cy = self.circle.pos
        self.circle.pos = (cx + 10, cy)

class RootClass(Widget):
    field = ObjectProperty(None)
    def __init__(self, **kwargs):
        super(RootClass, self).__init__(**kwargs)

class MyMainApp(App):
    def build(self):
        self.r = RootClass()
        return self.r

    def on_start(self, **kwargs):
        self.r.field.init_circle()

if __name__ == '__main__':
    Builder.load_file("my.kv")
    MyMainApp().run()

my.kv:

<RootClass>
    field: field_id
    BoxLayout:
        size: root.size
        orientation: "vertical"
        Field:
            id: field_id
            size_hint: 1, 0.9

        Button:
            size_hint: 1, 0.1
            text: "Move"
            on_press:
                root.field.move_circle()

Upvotes: 2

Views: 986

Answers (1)

ApuCoder
ApuCoder

Reputation: 2888

Method 1: Using bind by binding to a callback method,

class Field(Widget):
    def __init__(self, **kwargs):
        super(Field, self).__init__(**kwargs)
        # Bind a callback method, say here 'init_circle' to the prop. 'size' and 'pos'
        # so that whenever those prop. change the method will be called.
        # To prevent redrawing you may use method 'clear' or some other strategy.
        self.bind(size = self.init_circle, pos = self.init_circle)

    def init_circle(self, *args):
        with self.canvas:
    ...

Method 2: Using Clock by scheduling the process,

    def on_start(self, **kwargs):
        Clock.schedule_once(self.r.field.init_circle)

Upvotes: 1

Related Questions