I'm having trouble changing the color of a simple widget in Kivy.
I can set the color when I create the widget, but I can't change it afterwards.
Here is the simple layout definition file circletest.kv
. It defines a circle where the color (actually just the r, from rgba), position and size are all linked to variables in the widget class.
#:kivy 1.4.1
<CircleWidget>:
canvas:
Color:
rgba: self.r,1,1,1
Ellipse:
pos: self.pos
size: self.size
Here's the application circletest.py
. It creates and displays the simple widget. The color and position are successfully set when the object is created. When the widget is clicked the widget can change it's own position, but when I try to change the color nothing happens.
import kivy
kivy.require('1.4.1')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
Builder.load_file('circletest.kv')
class CircleWidget(Widget):
def __init__(s, **kwargs):
s.size= [50,50]
s.pos = [100,50]
s.r = 0
super(CircleWidget, s).__init__(**kwargs)
def on_touch_down(s, touch):
if s.collide_point(touch.x,touch.y):
s.pos = [s.pos[1],s.pos[0]] # This works
s.r = 1.0 # <---- This does nothing!
class TestApp(App):
def build(s):
parent = Widget()
w = CircleWidget()
parent.add_widget(w)
return parent
if __name__ == '__main__':
TestApp().run()
Can anyone see the problem?
UPDATE
Still not sure what the answer to this question is, but I do have a work around:
In the .kv file I pointed the color to a variable in my object. Works for extracting the initial color:
Color:
rgba: self.col
When I want to change the color from the .py file I loop through all the instructions in the canvas and modify the first one of type "Color". Obviously this is a hack, and won't work on widgets with more than one Color:
property:
for i in s.canvas.get_group(None):
if type(i) is Color:
i.r, i.g, i.b, i.a = v
break
I wrapped that all up in a property so it's neat to use:
class CircleWidget(Widget):
def get_col(s):
return s._col
def set_col(s,v):
for i in s.canvas.get_group(None):
if type(i) is Color:
i.r, i.g, i.b, i.a = v
break
s._col = v
col = property(get_col, set_col)
def __init__(s, **kwargs):
s.size= [50,50]
s.pos = [100,50]
s._col = (1,1,0,1)
super(CircleWidget, s).__init__(**kwargs)
def on_touch_down(s, touch):
if s.collide_point(touch.x,touch.y):
s.col = (s.col[::-1]) # Set to some other color
Seems to work for now. Please let me know if you know a better way of doing this. I'm sure there must be a simpler way, and that I'm missing something obvious!
See Question&Answers more detail:
os