Как мне изменить цвет моего виджета в 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()
Кто-нибудь может увидеть проблему?
ОБНОВИТЬ
Все еще не уверен, что ответ на этот вопрос, но у меня есть обходной путь:
В файле.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
Кажется, работает на данный момент. Пожалуйста, дайте мне знать, если вы знаете лучший способ сделать это. Я уверен, что должен быть более простой способ, и что я упускаю что-то очевидное!
2 ответа
В вашей первоначальной версии вы просто пропустили объявление свойства
from kivy.properties import NumericProperty
в шапке и
r = NumericProperty(0)
только под class CircleWidget(Widget):
Кроме того, вы заявляете, что ваш файл kv называется circletest.kv, но ваше приложение называется TestApp, поэтому вы должны изменить один из них, чтобы сделать его согласованным, иначе ваш файл kv не будет найден, но вы не сообщаете любая проблема с этим, я думаю, это всего лишь опечатка в вопросе. редактировать: только что увидел Builder.load_file
в порядке,
веселит.
Ответ от 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, так как оно реализует шаблон наблюдателя.
Переменная r
в вашем коде был обновлен, но это просто переменная, которая не дает никаких признаков того, что ее значение изменилось и не может быть связано с. Если вы заметили ваши изменения в pos
работать потому что pos
является ReferenceListProperty.
Общее правило для программирования в Kivy, если вы хотите изменить код в зависимости от свойства виджета / объекта, используйте свойство Kivy. Он предоставляет вам возможность наблюдать изменения свойств и корректировать ваш код соответствующим образом либо явно через события bind / on_property_name, либо неявно через язык kv, как упомянуто выше.