Reputation: 148
I need to draw a line inside a Widget. But I've seen that the relative position and size of the widget aren't setted until the init method finish.
How can I draw a graphic element inside a widget with his relative position and dimension while I instantiate the class? (I would like to avoid Kv lang)
class Track(Widget):
def __init__(self,**kw):
super(Track, self).__init__(**kw)
with self.canvas:
Color(1,0,0)
Line(points = (self.x, (self.y + self.height) / 2, self.x + self.width, (self.y + self.height) / 2))
In this way the line it's drawn using the initial size and position which are 100,100 and 0,0 but the Widget it's inside a Layout so I'd like to use the relative position and size and I'd like to drawn it in the init
Upvotes: 1
Views: 730
Reputation: 69
Demo of Inclement's Brillant answer!
The goal is to reposition a figure to the center of the widget
from kivy.app import App
from kivy.graphics.vertex_instructions import Line
class MyWidget(Widget):
def __init__(self):
super().__init__()
print(f"on init: {self.width}, {self.height}")
with self.canvas:
self.coordinate = Translate(0, 0)
Line(points=[0,0,100,100], width=20)
#Comment the following line
self.bind(pos=self.reposition, size=self.reposition)
def reposition(self, *args):
print(f"on reposition: {self.width}, {self.height}")
self.coordinate.xy = self.width/2, self.height/2
class myApp(App):
def build(self):
return MyWidget()
myApp().run()
Results:
on init: 100, 100
on reposition: 1000, 500
Before|After binding:
Upvotes: 0
Reputation: 29450
I would like to avoid Kv lang
I recommend discarding this restriction.
In this way the line it's drawn using the initial size and position which are 100,100 and 0,0 but the Widget it's inside a Layout so I'd like to use the relative position and size and I'd like to drawn it in the init
You have three options. The first is to draw it in a clock (kivy.clock.Clock
) scheduled function that runs after the widget has been positioned - it should be sufficient to do Clock.schedule_once(the_func, 0)
, with the 0
deferring the calculation to after the widget is positioned (assuming a normal layout) but before the next frame. The downside is that the line will then be fixed, and won't match the widget if if ever moves, e.g. potentially during window resize.
The second (and better) option is to draw the line as you are now, but bind to the widget pos and size a function that repositions it appropriately. e.g. self.bind(pos=self.line_setter, size=self.line_setter)
and have self.line_setter
be a method with self.line.points = [...]
as appropriate. You would also need to save a reference to the line with self.line = Line(...)
.
The third (and normally best) option is to use kv language, which automatically creates the bindings for you with no additional syntax.
Upvotes: 2