Keno
Keno

Reputation: 3955

Update position of child object widgets in Kivy (Python not .kv)

I have a parent widget that adds and positions custom widget objects, but when the window is resized they don't update their position...

import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Color, Line, Ellipse, Rectangle
from kivy.metrics import dp
from kivy.uix.widget import Widget


class circleChild(Widget):
    def __init__(self, *args, **kwargs):
        self.pos = kwargs.get('_pos')
        self.size = kwargs.get('_size')
        super(circleChild, self).__init__()
        with self.canvas:
            Color(0.4, 0.6, 0.9, 1)  # ConrflowerBlue
            Ellipse(pos=self.pos, size=self.size, width=dp(2))


class RootWidget(BoxLayout):
    def __init__(self, *args, **kwargs):
        BoxLayout.__init__(self, *args, **kwargs)
        self.bind(pos=self.draw)
        self.bind(size=self.draw)
        self.layout1 = BoxLayout()
        self.layout2 = BoxLayout(opacity=0.8)
        self.add_widget(self.layout1)
        self.add_widget(self.layout2)
        self.childrenAdded = False

    def draw(self, *args):
        with self.canvas.before:
            Color(.8, .8, .8, 1)  # LightGrey
            self.bg = Rectangle(pos=self.pos, size=self.size)
        self.layout1.canvas.clear()
        with self.layout1.canvas:
            Color(0, 0, 0, 1)  # Black
            Line(
                points=[
                    self.center_x, self.center_y - 200, self.center_x,
                    self.center_y + 200
                ],
                width=dp(2))
            Line(
                points=[
                    self.center_x - 200, self.center_y, self.center_x + 200,
                    self.center_y
                ],
                width=dp(2))
        if not self.childrenAdded:
            self.addChildren()

    def addChildren(self, *args):
        circle1 = circleChild(
            _pos=[self.center_x + 100, self.center_y + 100], _size=[100, 100])
        circle2 = circleChild(
            _pos=[self.center_x + 100, self.center_y - 200], _size=[100, 100])
        circle3 = circleChild(
            _pos=[self.center_x - 200, self.center_y + 100], _size=[100, 100])
        circle4 = circleChild(
            _pos=[self.center_x - 200, self.center_y - 200], _size=[100, 100])
        self.layout2.add_widget(circle1)
        self.layout2.add_widget(circle2)
        self.layout2.add_widget(circle3)
        self.layout2.add_widget(circle4)
        self.childrenAdded = True


class PositionChildren(App):
    title = "PositionChildren"

    def build(self):
        return RootWidget()


if __name__ == "__main__":
    PositionChildren().run()

Results in:

enter image description here

The problem is when resizing the window, this happens :

enter image description here

How would reposition the childWidgets in python?

Upvotes: 2

Views: 871

Answers (1)

eyllanesc
eyllanesc

Reputation: 244301

I see that you are complicating creating new properties like _pos or _size, instead you should only use the existing properties pos and size, on the other hand you are using the canvas at every moment, instead reusing the elements.

Considering the above, the simple solution is:

from kivy.app import App
from kivy.graphics import Color, Line, Ellipse, Rectangle
from kivy.metrics import dp
from kivy.uix.widget import Widget

class circleChild(Widget):
    def __init__(self, **kwargs):
        super(circleChild, self).__init__(**kwargs)
        self.draw()
        self.bind(pos=self.redraw, size=self.redraw)

    def draw(self):
        with self.canvas:
            Color(0.4, 0.6, 0.9, 1)  # ConrflowerBlue
            self.ellipse = Ellipse(width=dp(2))

    def redraw(self, *args):
        # reuse
        self.ellipse.pos = self.pos
        self.ellipse.size = self.size

class RootWidget(Widget):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        self.draw()
        self.bind(pos=self.redraw, size=self.redraw)

        self.circle1 = circleChild(size=[100, 100])
        self.circle2 = circleChild(size=[100, 100])
        self.circle3 = circleChild(size=[100, 100])
        self.circle4 = circleChild(size=[100, 100])
        for c in (self.circle1, self.circle2, self.circle3, self.circle4):
            self.add_widget(c)

    def draw(self):
        with self.canvas.before:
            Color(.8, .8, .8, 1)  # LightGrey
            self.bg = Rectangle(pos=self.pos, size=self.size)
            Color(0, 0, 0, 1)  # Black
            self.vline = Line(width=dp(2))
            self.hline = Line(width=dp(2))

    def redraw(self, *args):
        # reuse
        self.bg.pos = self.pos
        self.bg.size = self.size
        self.vline.points = [
            self.center_x, 
            self.center_y - 200, 
            self.center_x,
            self.center_y + 200
        ]
        self.hline.points=[
            self.center_x - 200, 
            self.center_y, 
            self.center_x + 200,
            self.center_y
        ]
        self.circle1.pos = [self.center_x + 100, self.center_y + 100]
        self.circle2.pos = [self.center_x + 100, self.center_y - 200]
        self.circle3.pos = [self.center_x - 200, self.center_y + 100]
        self.circle4.pos = [self.center_x - 200, self.center_y - 200]

class PositionChildren(App):
    title = "PositionChildren"

    def build(self):
        return RootWidget(size=(100, 100))

if __name__ == "__main__":
    PositionChildren().run()

Upvotes: 1

Related Questions