Как изменить цвет моего виджета в Kivy во время выполнения?

У меня возникли проблемы с изменением цвета простого виджета в Kivy. Я могу установить цвет при создании виджета, но потом не могу его изменить.

Вот простой файл определения макета circletest.kv. Он определяет круг, в котором цвет (фактически только r, из rgba), положение и размер связаны с переменными в классе виджетов.

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

Может ли кто-нибудь увидеть проблему?

UPDATE

Пока не уверен, что ответ на этот вопрос, но у меня есть работа вокруг:

В файле .kv я указал цвет на переменную в моем объекте. Работает для извлечения исходного цвета:

Color:
    rgba: self.col

Когда я хочу изменить цвет из .py файла, я просматриваю все инструкции на холсте и изменяю первый тип "Цвет". Очевидно, что это взломать и не будет работать с виджетами с более чем одним свойством 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

Кажется, сейчас работает. Пожалуйста, дайте мне знать, если вы знаете лучший способ сделать это. Я уверен, что должен быть более простой способ, и что я пропускаю что-то очевидное!

Ответ 1

В вашей начальной версии вы просто не указали объявление свойства

from kivy.properties import NumericProperty

в заголовке и

r = NumericProperty(0)

чуть ниже class CircleWidget(Widget):

также вы указываете, что ваш файл kv называется circletest.kv, но ваше приложение называется TestApp, поэтому вы должны изменить один из них, чтобы сделать их согласованными, или ваш файл kv не будет найден, но поскольку вы Я не сообщаю о каких-либо проблемах, думаю, это только опечатка в вопросе. edit: просто увидел Builder.load_file ok,

приветствий.

Ответ 2

Ответ 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, поскольку оно реализует шаблон наблюдателя.

Переменная r в вашем коде была обновлена, но это просто переменная, которая не дает никаких указаний на то, что это значение изменилось и не может быть связано. Если вы заметили изменения в pos, потому что pos - это ReferenceListProperty.

Общее правило для программирования в Kivy, если вы хотите изменить код в зависимости от свойства виджета/объекта, используйте Kivy Property. Он предоставляет вам возможность Наблюдать за изменениями свойств и соответственно корректировать ваш код через bind/on_property_name или неявно через kv-язык, как указано выше.