如何在运行时更改Kivy中我的小部件的颜色?

时间:2012-10-21 11:49:17

标签: python kivy

我无法在Kivy中更改简单小部件的颜色。 我可以在创建窗口小部件时设置颜色,但之后我无法更改它。

这是简单的布局定义文件circletest.kv。它定义了一个圆圈,其中颜色(实际上只是r,来自rgba),位置和大小都链接到widget类中的变量。

#:kivy 1.4.1

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

这是应用程序circletest.py。它创建并显示简单的小部件。创建对象时成功设置颜色和位置。单击小部件时,小部件可以更改它自己的位置,但是当我尝试更改颜色时,没有任何反应。

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()

有人能看到问题吗?

更新

仍然不确定这个问题的答案是什么,但我确实有一个解决方法:

在.kv文件中,我将颜色指向对象中的变量。用于提取初始颜色:

Color:
    rgba: self.col

当我想从.py文件中更改颜色时,我遍历画布中的所有指令并修改第一个“Color”类型。显然这是一个hack,并且不适用于具有多个Color:属性的小部件:

for i in s.canvas.get_group(None):
    if type(i) is Color:
        i.r, i.g, i.b, i.a = v
        break

我把它全部包裹在一个属性中,所以它很好用:

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

现在似乎工作。如果您知道更好的方法,请告诉我。我敢肯定必须有一种更简单的方法,而且我错过了一些明显的东西!

2 个答案:

答案 0 :(得分:17)

tshirtman的答案是正确的,这里是对正在发生的事情的解释。

设置

时在kv文件中
<CircleWidget>:
    canvas:
        Color:
            rgba: self.r, 1, 1, 1
        Ellipse:
            pos: self.pos
            size: self.size

只要rgba: self.r, 1, 1, 1的值发生变化,行rgba就会尝试更新r的值。这是通过绑定在kv语言中隐式完成的,可以在kivy Property上实现,因为它实现了Observer Pattern

代码中的变量r已更新,但它只是一个变量,它不会提供任何值已更改且无法绑定的指示。如果您注意到对pos的更改有效,因为pos是一个ReferenceListProperty。

在Kivy中编程的一般规则,如果要根据窗口小部件/对象的属性更改代码,请使用Kivy Property。它为Observe Property changes提供了选项,并相应地通过bind / on_property_name事件或通过上述kv语言隐式调整您的代码。

答案 1 :(得分:14)

在您的初始版本中,您只是错过了属性声明

from kivy.properties import NumericProperty
标题中的

r = NumericProperty(0)

class CircleWidget(Widget):

另外,您声明您的kv文件名为circletest.kv,但您的应用程序名为TestApp,因此您应更改其中一个以使其一致,否则您的kv文件将无法找到,但是不报告任何问题,我想这只是问题中的一个错字。编辑:刚看到Builder.load_file确定,

欢呼声。