pythonkivy

Image not reloading - kivy python


So I'm very new to Kivy, and the point here is to have a random integer cycle through 3 random integers and change images corresponding to the integers, with a clock checking this every second. It does show its being changed, even the image source seems to be changing but I'm not seeing any update, just a white screen (And yes, the images did work before when set manually, without this code). Some good help and explanation would go a long way, thanks!

main.py

import random

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.clock import Clock


def rand_num():
    num = random.randint(1,3)
    return num

class FaceImage(BoxLayout):
    def img_timer(self):
        Clock.schedule_interval(self.swap_face, 1)
    
    def run_face(img_name):
        num = rand_num()
        if num == 1:
            img_name = 'smile1.png'
        elif num == 2:
            img_name = 'smile2.png'
        elif num == 3:
            img_name = 'smile3.png'
        return img_name

    def swap_face(self, dt):
        self.image = FaceImage().ids.face
        self.image.source = self.run_face()
        print(self.image.source)
        self.image.reload()
    

class ServotApp(App):
    def __init__(self, **kwargs):
        super(ServotApp, self).__init__(**kwargs)
        self.img_obj = FaceImage()
        self.img_obj.img_timer()

    
    def build(self):
        face_img = FaceImage()
        return face_img
        

if __name__ == "__main__":
    ServotApp().run()

servot.kv

#:kivy 2.3.1
<FaceImage>:
    orientation: 'vertical'
    canvas:
        Color:
            rgba: 1, 0.93, 0.75, 1
        Rectangle:
            pos: self.pos
            size: self.size
    Image:
        id: face
        size: self.size

Solution

  • A couple problems with your code. First, whenever you use FaceImage() you are creating a new instance of FaceImage. So your __init__() code is creating a new instance of FaceImage (which is not the instance that you are expecting to see in your App window) and calling img_timer() on that instance. The result is that you are swapping sources in an Image that is not part of your display.

    Similarly, your swap_face() method is creating yet another instance of FaceImage which is also not in your App display.

    To fix these problems, you can eliminate your __init__() method completely. Then modify your build() method to call your img_timer(), and modify swap_face() method to use the actual instance of FaceImage that is in your App display. Your run_face() method should have self as its only arg. With those corrections, you also do not need a call to reload() the Image. Here is a modified version of your code with those corrections:

    import random
    
    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    from kivy.uix.image import Image
    from kivy.clock import Clock
    
    def rand_num():
        num = random.randint(1, 3)
        return num
    
    
    class FaceImage(BoxLayout):
        def img_timer(self):
            Clock.schedule_interval(self.swap_face, 1)
    
        def run_face(self):
            num = rand_num()
            if num == 1:
                img_name = 'smile1.png'
            elif num == 2:
                img_name = 'smile2.png'
            elif num == 3:
                img_name = 'smile3.png'
            return img_name
    
        def swap_face(self, dt):
            self.image = self.ids.face
            self.image.source = self.run_face()
            print(self.image.source)
    
    
    class ServotApp(App):
        def build(self):
            face_img = FaceImage()
            face_img.img_timer()
            return face_img
    
    
    if __name__ == "__main__":
        ServotApp().run()