animate Kivy Bezier curve with custom width ? (a bit silly question)
Question:
update: After discussing with others, I decided that it is a bit silly question. I wanted to animate Bezier curve with changed width, but it has no width property. with Line Bezier, I can change width, but then can’t animate.
I can’t change witdh
of Bezier
curve like Line
.
here is the code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *
class MyLayout(Widget):
def __init__(self):
super(MyLayout, self).__init__()
with self.canvas:
self.L=Bezier(points=[200,450,500,300,600,150],width=12)
self.k=Line (bezier=[100,350,400,200,500,50 ],width=12)
class MyApp(App):
def __init__(self):
super(MyApp, self).__init__()
def build(self):
return MyLayout()
if __name__=="__main__":
MyApp().run()
the problem is,
the upper curve isn’t width=12
.
I think that’s because Kivy’s Bezier Class has no attribute width
cuz when I do it on kv
lang, it gives me AttributeError: 'kivy.graphics.vertex_instructions.Bezier' object has no attribute 'width'
. Well, why not using Line
with bezier
? I want to use Animation
on it and when I try to on Line
with bezier
, I get AttributeError: attribute 'bezier' of 'kivy.graphics.vertex_instructions.Line' objects is not readable
.
so the question,
how can I change width
of Bezier
. if it is not possible, is there any way like finding the y of cruve (or ys) for given x so I can put Ellipse
on these points and resize them to simulate width ?
thanks and pardon my english ♥
Answers:
The Bezier
has no width
property, but the Line
does. So you can animate that width
. An easy way to do that is by animating a NumericProperty
that holds the width. Here is a modified version of your code that does that:
from kivy.animation import Animation
from kivy.app import App
from kivy.clock import Clock
from kivy.properties import NumericProperty
from kivy.uix.widget import Widget
from kivy.graphics import *
class MyLayout(Widget):
line_width = NumericProperty(12)
def __init__(self):
super(MyLayout, self).__init__()
with self.canvas:
self.L=Bezier(points=[200,450,500,300,600,150],width=self.line_width)
self.k=Line (bezier=[100,350,400,200,500,50 ],width=self.line_width)
def on_line_width(self, instance, new_width):
self.k.width = new_width
class MyApp(App):
def build(self):
Clock.schedule_once(self.anim)
return MyLayout()
def anim(self, dt):
a = Animation(line_width=3)
a.start(self.root)
if __name__=="__main__":
MyApp().run()
If you build the Line
in kv
, then you don’t even need the on_line_width()
method since kivy will do the binding for you.
The line can use bezier:
, example:
Line:
bezier:[n1,n2,n3,n4]
width:3
This is a Line
, not a Bezier
, but you get the same result…
One example:
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.boxlayout import BoxLayout
posicao=[]
class Draw(BoxLayout):
def __init__(self, **kwargs):
super(Draw, self).__init__(**kwargs)
def on_touch_down(self,touch):
posicao.append(touch.pos)
def on_touch_up(self,touch):
posicao.clear()
def on_touch_move(self,touch):
Line = Builder.load_string(
"""
FloatLayout:
canvas:
Color:
rgba:11,.1,1,1
Line:
points: {pos}
width:14
""".format(pos=(touch.pos, posicao[0])))
self.add_widget(Line)
posicao.clear()
posicao.append(touch.pos)
class Code(App):
def build(self):
return Draw()
if __name__ == '__main__':
Code().run()
Or:
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import *
posi = []
Builder.load_string(
"""
<Draw>:
""")
class Draw(BoxLayout):
def __init__(self, **kwargs):
super(Draw, self).__init__(**kwargs)
def on_touch_down(self,touch):
posi.clear()
posi.append(touch.pos)
def on_touch_up(self,touch):
posi.clear()
def on_touch_move(self,touch):
with self.canvas:
Line(points=[posi[0], touch.pos],width=14)
posi.clear()
posi.append(touch.pos)
class Code(App):
def build(self):
return Draw()
if __name__ == '__main__':
Code().run()
update: After discussing with others, I decided that it is a bit silly question. I wanted to animate Bezier curve with changed width, but it has no width property. with Line Bezier, I can change width, but then can’t animate.
I can’t change witdh
of Bezier
curve like Line
.
here is the code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *
class MyLayout(Widget):
def __init__(self):
super(MyLayout, self).__init__()
with self.canvas:
self.L=Bezier(points=[200,450,500,300,600,150],width=12)
self.k=Line (bezier=[100,350,400,200,500,50 ],width=12)
class MyApp(App):
def __init__(self):
super(MyApp, self).__init__()
def build(self):
return MyLayout()
if __name__=="__main__":
MyApp().run()
the problem is,
the upper curve isn’t width=12
.
I think that’s because Kivy’s Bezier Class has no attribute width
cuz when I do it on kv
lang, it gives me AttributeError: 'kivy.graphics.vertex_instructions.Bezier' object has no attribute 'width'
. Well, why not using Line
with bezier
? I want to use Animation
on it and when I try to on Line
with bezier
, I get AttributeError: attribute 'bezier' of 'kivy.graphics.vertex_instructions.Line' objects is not readable
.
so the question,
how can I change width
of Bezier
. if it is not possible, is there any way like finding the y of cruve (or ys) for given x so I can put Ellipse
on these points and resize them to simulate width ?
thanks and pardon my english ♥
The Bezier
has no width
property, but the Line
does. So you can animate that width
. An easy way to do that is by animating a NumericProperty
that holds the width. Here is a modified version of your code that does that:
from kivy.animation import Animation
from kivy.app import App
from kivy.clock import Clock
from kivy.properties import NumericProperty
from kivy.uix.widget import Widget
from kivy.graphics import *
class MyLayout(Widget):
line_width = NumericProperty(12)
def __init__(self):
super(MyLayout, self).__init__()
with self.canvas:
self.L=Bezier(points=[200,450,500,300,600,150],width=self.line_width)
self.k=Line (bezier=[100,350,400,200,500,50 ],width=self.line_width)
def on_line_width(self, instance, new_width):
self.k.width = new_width
class MyApp(App):
def build(self):
Clock.schedule_once(self.anim)
return MyLayout()
def anim(self, dt):
a = Animation(line_width=3)
a.start(self.root)
if __name__=="__main__":
MyApp().run()
If you build the Line
in kv
, then you don’t even need the on_line_width()
method since kivy will do the binding for you.
The line can use bezier:
, example:
Line:
bezier:[n1,n2,n3,n4]
width:3
This is a Line
, not a Bezier
, but you get the same result…
One example:
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.boxlayout import BoxLayout
posicao=[]
class Draw(BoxLayout):
def __init__(self, **kwargs):
super(Draw, self).__init__(**kwargs)
def on_touch_down(self,touch):
posicao.append(touch.pos)
def on_touch_up(self,touch):
posicao.clear()
def on_touch_move(self,touch):
Line = Builder.load_string(
"""
FloatLayout:
canvas:
Color:
rgba:11,.1,1,1
Line:
points: {pos}
width:14
""".format(pos=(touch.pos, posicao[0])))
self.add_widget(Line)
posicao.clear()
posicao.append(touch.pos)
class Code(App):
def build(self):
return Draw()
if __name__ == '__main__':
Code().run()
Or:
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import *
posi = []
Builder.load_string(
"""
<Draw>:
""")
class Draw(BoxLayout):
def __init__(self, **kwargs):
super(Draw, self).__init__(**kwargs)
def on_touch_down(self,touch):
posi.clear()
posi.append(touch.pos)
def on_touch_up(self,touch):
posi.clear()
def on_touch_move(self,touch):
with self.canvas:
Line(points=[posi[0], touch.pos],width=14)
posi.clear()
posi.append(touch.pos)
class Code(App):
def build(self):
return Draw()
if __name__ == '__main__':
Code().run()