0

I want to change my picture in a box, I am trying to do that with the help of id's. I have tried many solutions and have search for well over 3 hours but I couldn't get anything right so I would be grateful for any help. I am also quite new to Kivy.

I tried changing:

self.ids.rec.source = 'download.jpg'

to(as suggested by Python - Kivy: AttributeError: 'super' object has no attribute '__getattr__' when trying to get self.ids)

self.parent.parent.ids

It did not work, only changed my error to:

 AttributeError: 'NoneType' object has no attribute 'parent'

Tried to fiddle with it on my own but also couldn't really do much except change the error to an another one.

This is my python file:

from kivy.app import *
from kivy.uix.button import *
from kivy.graphics import *
from kivy.uix.widget import *
from kivy.uix.label import *
from kivy.uix.floatlayout import *
from kivy.uix.boxlayout import *
from kivy.uix.relativelayout import *
from kivy.properties import ListProperty, StringProperty,ObjectProperty
x = []
f = []
#---------------------------------------------------------------------------------
class Picture(FloatLayout):
    def __init__(self, **kwargs):
        super(Picture, self).__init__(**kwargs)
    def change(self,**kwargs):
        y = len(x)
        if y % 2 == 0:
            self.ids.rec.source = 'download.jpg'
            tilesource = 'download.jpg'
            print("aaaa")
        else:
            tilesource = 'images.jpg'
            print("bbbbb")

#---------------------------------------------------------------------------------
class TileWidget(FloatLayout):
    def __init__(self, **kwargs):
        super(TileWidget, self).__init__(**kwargs)
        self.pos = (0, 0)
        self.size = (1,1)
        d = Picture()
        self.add_widget(d)

    def swap(self):
        x.append("0")
        Picture().change()
#---------------------------------------------------------------------------------
class langApp(App):
    def build(self):
        return TileWidget()
#---------------------------------------------------------------------------------

if __name__ == '__main__':
    langApp().run()


And this is my .kv file:

    #:kivy 1.11.1
<TileWidget>:
    FloatLayout:
        pos: 0,0
        size: root.width,root.height
        Button:
            text: 'Last'
            pos_hint: {'x':.25,'y':.1}
            size_hint: .1,.1
        Button:
            text: 'Stop'
            pos_hint: {'x':.45,'y':.1}
            size_hint: .1,.1
        Button:
            on_press: root.swap()
            text: 'Next'
            pos_hint: {'x':.65,'y':.1}
            size_hint: .1,.1
<Picture>:
    pos_hint: {'x':.25,'y':.4}
    canvas:
        Rectangle:
            id: rec
            size: self.size[0]*0.5,self.size[1]*0.5
            pos: self.pos[0],self.pos[1]
            source: "images.jpg"

Here is my full error log:

 Traceback (most recent call last):
   File "kivy\properties.pyx", line 861, in kivy.properties.ObservableDict.__getattr__
 KeyError: 'rec'

 During handling of the above exception, another exception occurred:

 Traceback (most recent call last):
   File "c:/Users/Leon/mobile/main.py", line 45, in <module>
     langApp().run()
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\app.py", line 950, in run
     runTouchApp()
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\base.py", line 582, in runTouchApp
     EventLoop.mainloop()
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\base.py", line 347, in mainloop
     self.idle()
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\base.py", line 391, in idle
     self.dispatch_input()
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\base.py", line 342, in dispatch_input
     post_dispatch_input(*pop(0))
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\base.py", line 248, in post_dispatch_input
     listener.dispatch('on_motion', etype, me)
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\core\window\__init__.py", line 1412, in on_motion
     self.dispatch('on_touch_down', me)
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\core\window\__init__.py", line 1428, in on_touch_down
     if w.dispatch('on_touch_down', touch):
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\uix\widget.py", line 545, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\uix\widget.py", line 545, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\uix\behaviors\button.py", line 151, in on_touch_down
     self.dispatch('on_press')
   File "kivy\_event.pyx", line 705, in kivy._event.EventDispatcher.dispatch
   File "kivy\_event.pyx", line 1248, in kivy._event.EventObservers.dispatch
   File "kivy\_event.pyx", line 1132, in kivy._event.EventObservers._dispatch
   File "C:\Users\Leon\mobile\env\lib\site-packages\kivy\lang\builder.py", line 57, in custom_callback
     exec(__kvlang__.co_value, idmap)
   File "c:\Users\Leon\mobile\lang.kv", line 15, in <module>
     on_press: root.swap()
   File "c:/Users/Leon/mobile/main.py", line 37, in swap
     Picture().change()
   File "c:/Users/Leon/mobile/main.py", line 19, in change
     self.ids.rec.source = 'download.jpg'
   File "kivy\properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'
Leon Kardaš
  • 101
  • 8

1 Answers1

0

Two problems with your code:

The swap() method:

def swap(self):
    x.append("0")
    Picture().change()

is creating a new instance of Picture and calling change() on that new instance. That will have no effect on the instance of Picture that is actually in your GUI. An easy way to fix that is to keep a reference to the Picture instance that is actually in your GUI, and use that in the swap() method:

class TileWidget(FloatLayout):
    def __init__(self, **kwargs):
        super(TileWidget, self).__init__(**kwargs)
        self.pos = (0, 0)
        self.size = (1,1)
        self.d = Picture()
        self.add_widget(self.d)

    def swap(self):
        x.append("0")
        self.d.change()

The second problem is that you cannot use ids for canvas instructions, but you can use groups. So, you can place the Rectangle instruction in a group of its own:

<Picture>:
    pos_hint: {'x':.25,'y':.4}
    canvas:
        Rectangle:
            group: 'rec'  # place this instruction in its own group
            size: self.size[0]*0.5,self.size[1]*0.5
            pos: self.pos[0],self.pos[1]
            source: "images.jpg"

Then you can use that group to modify the Rectangle:

def change(self,**kwargs):
    y = len(x)
    if y % 2 == 0:
        rec = self.canvas.get_group('rec')[0]
        rec.source = 'download.jpg'
        tilesource = 'download.jpg'
        print("aaaa")
    else:
        tilesource = 'images.jpg'
        print("bbbbb")
John Anderson
  • 35,991
  • 4
  • 13
  • 36