I am trying to reference the source image of a Rectangle object in a canvas. I don't seem to find the correct code that will correctly reference it. Trying with ids doesn't work because the rectangle cant be given an id, only a group. Therefore, I need to use a group, but this is complex because I have several embedded attributes. Can anyone help? The current solution using self.canvas.get_group("firstQelement")[0].source
I found online when a user had an issue with a similar problem. I have tried using different paths to get to the group, including referencing ids and layouts.
AnswerCycle
refers to a pre formatted toggle button
Kivy File:
<QuestionDisplay>:
name: "questionDisplay"
RelativeLayout:
canvas.before:
Color:
rgba: utils.get_color_from_hex('#90E0EF')
Rectangle:
pos: self.pos
size: self.size
GridLayout:
padding: 20
spacing: 20
cols: 1
size: root.width, root.height
Title:
id: questionTitle
Image:
canvas.before:
Color:
rgba: utils.get_color_from_hex('#0077B6')
Rectangle:
size: self.size
pos: self.pos
id: mainQuestion
source: "empty.png"
size_hint_y: None
size: root.width, 195
GridLayout:
size_hint_y: None
size: root.width, 200
cols: 2
AnswerCycle:
id: firstQ
canvas.after:
Rectangle
group: "firstQelement"
pos: self.pos
size: self.size
source: "empty.png"
AnswerCycle:
id: secondQ
canvas.after:
Rectangle
group: "secondQelement"
pos: self.pos
size: self.size
source: "empty.png"
AnswerCycle:
id: fourthQ
canvas.after:
Rectangle
group: "thirdQelement"
pos: self.pos
size: self.size
source: "empty.png"
AnswerCycle:
id: thirdQ
canvas.after:
Rectangle
group: "fourthQelement"
pos: self.pos
size: self.size
source: "empty.png"
Python Code:
if Value.correctButtonNumber == 1: self.canvas.get_group("firstQelement")[0].source = "cAnswer.png"
if Value.correctButtonNumber == 2: self.canvas.get_group("secondQelement")[0].source = "cAnswer.png"
if Value.correctButtonNumber == 3: self.canvas.get_group("thirdQelement")[0].source = "cAnswer.png"
if Value.correctButtonNumber == 4: self.canvas.get_group("fourthQelement")[0].source = "cAnswer.png"
Error:
if Value.correctButtonNumber == 1: self.canvas.get_group("firstQelement")[0].source = "cAnswer.png"
IndexError: list index out of range
Minimal Reproducible Example:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
import random
APP_KV = """
<CanvasTest>:
BoxLayout:
canvas.after:
Color:
rgba: 0, 1, 0, 1
Rectangle:
group: 'rectangle'
size: 400, 200
pos: self.pos
Color:
rgba: 1, 0, 0, 1
Ellipse:
group: 'ellipse'
size: 200, 100
pos: self.pos
"""
class CanvasTest(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
print(self.BoxLayout.canvas.after.get_group('rectangle'))
class MainApp(App):
def build(self):
self.root = Builder.load_string(APP_KV)
return CanvasTest()
if __name__ == '__main__':
MainApp().run()
When BoxLayout:
is removed, from both the KV script and the print statement, this code works correctly.
Here is a modified version of your code that changes the source
attribute of the Rectangle
:
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
APP_KV = """
<CanvasTest>:
BoxLayout:
id: box
canvas.after:
Color:
rgba: 0, 1, 0, 1
Rectangle:
group: 'rectangle'
size: 400, 200
pos: self.pos
Color:
rgba: 1, 0, 0, 1
Ellipse:
group: 'ellipse'
size: 200, 100
pos: self.pos
"""
class CanvasTest(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_once(self.info, 2)
def info(self, dt):
rect = self.ids.box.canvas.after.get_group('rectangle')[0]
rect.source = 'tester.png'
class MainApp(App):
def build(self):
self.root = Builder.load_string(APP_KV)
return CanvasTest()
if __name__ == '__main__':
MainApp().run()
I added the id
of box
to the BoxLayout
in the APP_KV
to allow access to that BoxLayout
. Note that you shouldn't try to access ids
in the __init__()
method because they typically have not been set yet at that point. That is why I used Clock.schedule_once()
.