Caaarlos Caaarlos - 2 months ago 15
Python Question

Kivy position of a GridLayout's children always returns (0,0)

When I add some element to my GridLayout, if want to get the element postion, Kivy always returns (0,0), but it not true, because the elements are correctly positioned on my windows.

class ImageButton(ButtonBehavior, Label):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.text = 'hello'

def add_sources(self, sources):
print(self.pos) #(0,0), but is not (0,0)
self.add_widget(Label(text='foo', pos=self.pos))


And this is my main class.

class MyClass(Widget):

my_layout = ObjectProperty(GridLayout())

def __init__(self):
super().__init__()
self.load_layout()

def load_map(self):
self.my_layout.rows = 2
self.my_layout.cols = 2
self.draw_ui()

def draw_ui(self):
a = ImageButton()
b = ImageButton()
c = ImageButton()
d = ImageButton()

self.my_layout.add_widget(a)
self.my_layout.add_widget(b)
self.my_layout.add_widget(c)
self.my_layout.add_widget(d)

a.add_sources(0)
b.add_sources(1)
c.add_sources(0)
d.add_sources(1)


Why getting the widget's position returns me (0,0)? What am I doing wrong?

This is what I get:

I'm getting this

But I want the "foo" string in front of each "hello" string.

How can I do this?

Answer

The pos is equal to [0,0] at the first frame of the kivy GUI loop, when you print it. It changes a bit later. You have two ways of solving this problem:

  1. Wait till the second frame, when pos is updated as expected.
  2. Bind the pos instead of just assigning it once at the beginning.

Solution 1) example:

from kivy.clock import mainthread

class ImageButton(ButtonBehavior, Label):
    ...
    @mainthread
    def add_sources(self, sources):
        self.add_widget(Label(text='foo', pos=self.pos))

Solution 2) example:

class ImageButton(ButtonBehavior, Label):
    ...
    def add_sources(self, sources):
        self.add_widget(Label(text='foo', pos=self.setter('pos')))
Comments