In my previous post, I explained the use of
to_widget property as a way of transforming relative coordinates to absolute coordinates. In this post I will explain how do we transform coordinates between a particular widget and its parent. Basically, we just need to use the
to_local methods instead. However, these methods causes much more confusion than the transformation into absolute coordinates.
Let’s work with exactly the same example of the previous post. Following is the Kivy language code.
<RelativeLayout>: pos: 100,100 size_hint: .6,.6 canvas: Line: rectangle: 0,0, self.width, self.height <Relatives>: RelativeLayout: Button: pos: 0,0 size_hint: .4,.3 text: "Press Me!" on_press: text = root.test(*args)
Here is the output of that code:
And following is the Python code, in which we just changed the
to_widget methods for
from kivy.app import App from kivy.uix.relativelayout import RelativeLayout class Relatives (RelativeLayout): def test(self, inst): print "inst.pos = " + str(inst.pos) to_parent = inst.to_parent(*inst.pos) print "to_parent = " + str(to_parent) to_local = inst.to_local(*to_parent) print "to_local = " + str(to_local) class RelativesApp(App): def build(self): return Relatives() RelativesApp().run()
When we press the
Button instance, we get the following output in the terminal.
inst.pos = [0, 0] to_parent = (0, 0) to_local = (0, 0)
It seems like it didn’t work because the
to_parent output is the same. Why? Let’s give this a second thought. The coordinate
inst.pos is the position where the
Button instance is located relative to its parent. So, we already have a coordinate relative to its parent. When we call on the
to_parent method, we are actually requesting the coordinate on the same coordinate system.
Most of the time, what we probably want is obtaining the coordinate on the parent’s coordinate system. So instead on calling on
inst.to_parent, we should call on the
inst.parent.to_parent. Equivalently, we need to call on
inst.parent.to_local, instead of just
inst.to_local. The following code contains the correction.
from kivy.app import App from kivy.uix.relativelayout import RelativeLayout class Relatives (RelativeLayout): def test(self, inst): print "inst.pos = " + str(inst.pos) to_parent = inst.parent.to_parent(*inst.pos) print "to_parent = " + str(to_parent) to_local = inst.parent.to_local(*to_parent) print "to_local = " + str(to_local) class RelativesApp(App): def build(self): return Relatives() RelativesApp().run()
And here is the output.
inst.pos = [0, 0] to_parent = (100, 100) to_local = (0, 0)
Now, we are getting coordinates relative to
Relatives as you might be expecting.
Just to make sure you understand, please try the following exercise. For the above example, would the statement
print str(inst.parent.parent.to_parent(*inst.pos)) print the same terminal output as
Think about it before read the answer.
Answer: Since we are sending the coordinate (0, 0) directly as parameter to the
Relatives instance without a way to specify that it initially belong to the
Button instance, then the answer is no. In fact, in this particular case, the output is exactly the same.
Maybe it is clearer if I you just check the following code which is the real equivalent to
to_parent = inst.parent.to_parent(*inst.pos) print inst.parent.parent.to_parent(*to_parent)
As you can see, there are two steps to get to the absolute coordinates traversing the relative layouts. Of course, this just apply to this particular example of two relative layouts.