Search code examples
pythonpython-3.xloopsdictionarykivy

KIVY loop through images on external condition


I am trying to make a children's learning app using KIVY and gTTS where a child will be shown a random image and will have to identify it by saying what it is ("square" for square, "three" for 3 etc).

So far I have the menus working fine. I am using random.choice() in a dictionary where the value is the image path and the key is "the name"

If I open the relevant screen the image is correctly selected at random and displayed using def on_pre_enter(self, *args): and gTTS kicks in fine as well using def on_enter(self, *args): but only ONCE

I want it to load a new random image once the user replies to the previous one for an X amount of loops but no matter what I try I cannot get it to work (I thought of putting everything on a for x in range() loop as well as using a counter on a while X < Y: but without any success).

here's my .py file

import random
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty


class MenuWindow(Screen):
    pass

class ShapeGame(Screen):
    rand_shape = StringProperty()
    def on_pre_enter(self, *args):        
        random_shape = {"square":'shapes/square.png', "triangle":'shapes/triangle.jpg', "circle":'shapes/circle.jpg'}
        random_shape_key, random_shape_value = random.choice(list(random_shape.items()))
        print(random_shape_key)
        self.rand_shape_key = random_shape_key
        self.rand_shape = random_shape_value
        
    def on_enter(self, *args):
        print(self.random_shape_key)

class WindowManager(ScreenManager):
    pass

class MainApp(App):  
    def build(self):
        return Builder.load_file('Main.kv')

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

and my .kv file

#:kivy 2.0
WindowManager:
    MenuWindow:
    ShapeGame:

<MenuWindow>:
    name: "menu"
    BoxLayout:
        orientation: "vertical"
        size: root.width, root.height

        Label:
            id:"menu"
            text: "Menu Screen"
            font_size: 34
            
        BoxLayout:
            size_hint: 1.0, 0.2
            Button:
                text: "Shape Game"
                font_size: 22
                on_release:
                    app.root.current = "shapes"
                    root.manager.transition.direction = "left"
                
        Button:
            text: "Exit"
            font_size: 22
            size_hint: 1.0, 0.2
            on_release: app.root.current = exit() 

<ShapeGame>:
    name: "shapes"
    id: ShapeGame
    BoxLayout:
        orientation: "vertical"
        size: root.width, root.height
        Image:
            id:"shapes"
            screen: ShapeGame
            source: self.screen.rand_shape
            before_source: self.source

        BoxLayout:
            size_hint: 1.0, 0.2
            size: root.width, root.height
            Button:
                text: "Menu"
                on_release:
                    app.root.current = "menu"
                    root.manager.transition.direction = "right"
            Button:
                text: "Exit"
                on_release:
                    app.root.current = exit()

and the entire repo


Solution

  • Not sure I can follow your problem, assuming that you want to shuffle images on entering screen after some time until some value reaches its limit.

    For that you can use Clock.schedule_interval with some waiting time, say 2.0 sec.

    Thus your ShapeGame will now look like,

    class ShapeGame(Screen):
        rand_shape = StringProperty()
        count = 0
    
        def on_pre_enter(self, *args):
            self.count = 0
            self.change_event = Clock.schedule_interval(self.chage_photo, 2.0)
            
        def chage_photo(self, *args):
            if self.count < 3:
                self.count += 1
            else:
                self.change_event.cancel()
            random_shape = {"square":'shapes/square.png', "triangle":'shapes/triangle.jpg', "circle":'shapes/circle.jpg'}
            random_shape_key, random_shape_value = random.choice(list(random_shape.items()))
            print(random_shape_key)
            self.rand_shape_key = random_shape_key
            self.rand_shape = random_shape_value
    

    You should change source: self.screen.rand_shape to source: root.rand_shape.

    You may also trigger the same action by a button instead of using Clock.schedule.