Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I change the color of my widget in Kivy at run time?

Tags:

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!

like image 290
Andy Avatar asked Oct 21 '12 11:10

Andy


People also ask

What color system does KIVY use?

Kivy's colours are RGB(A) - don't confuse the colour space with the in-memory representation of the colour. Ultimately RGB measures each of the red, green and blue colour components on the scale from lightness zero (black) to maximum lightness (pure red/blue/green, if you like).

How do you change the widget color in flutter?

The Container widget has a color property. Your custom widget can also have any property such as color or size or colorChild . When you want to access the colorChild property of a StatefulWidget you use widget. colorChild , when it has no state, you can simply use colorChild .


1 Answers

The answer by tshirtman is correct, here is the explanation of what's going on.

In your kv file when you set

<CircleWidget>:     canvas:         Color:             rgba: self.r, 1, 1, 1         Ellipse:             pos: self.pos             size: self.size 

The line rgba: self.r, 1, 1, 1 tries to update the value of rgba whenever there is a change to the value of r. This is done implicitly in kv language by binding, which can be done on a kivy Property as it implements a Observer Pattern.

The variable r in your code was updated but it's just a variable that doesn't provide any indication that it's value has changed and can not be bound to. If you notice your changes to pos work because pos is a ReferenceListProperty.

General rule for programming in Kivy, if you want to change code depending on a property of a Widget/Object use a Kivy Property. It provides you the option to Observe Property changes and adjust your code accordingly either explicitly through bind/on_property_name events or implicitly through kv language as mentioned above.

like image 200
qua-non Avatar answered Oct 18 '22 08:10

qua-non