Search code examples
python-3.xkivykivy-languagekivymdthonny

how to make a loop to add multiple button


So i'm making a game for a class project and i want to add a grid of button, the size don't matter but after 2 day of try i m lost here is my python code:

import numpy as np
from collections import namedtuple

from kivy.app import App

from kivy.clock import Clock

from kivy.core.audio import SoundLoader
from kivy.core.window import Window
from kivy.graphics import Canvas
from kivy.graphics import Rectangle
from kivy.lang import Builder

from kivy.properties import ObjectProperty
from kivy.properties import ListProperty

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.screenmanager import NoTransition 
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.widget import Widget

field = namedtuple('field', ['rows', 'cols'])
FIELD = field(30, 60)

global a
a = "play"

        
class Jeu(Screen):     
    #here is the screen for the button grid
    #
    #
    #
    def test(self):
        Clock.schedule_interval(the_callback,0.1)
    def stop(self):
        Clock.unschedule(the_callback)

class MenuScreen(Screen):     
    pass
            
class RuleScreen (Screen):
    pass

class SettingsScreen(Screen):
    sound=SoundLoader.load('oui.wav')
    def fullscreen(self):
        name = self.ids.fullscreen.text
        if  Window.fullscreen == True:
            self.ids.fullscreen.text = 'Fullscreen off'
            Window.fullscreen = False
        else:
            self.ids.fullscreen.text = 'Fullscreen on'
            Window.fullscreen = True
    
    def music(self):
        sound=SoundLoader.load('oui.wav')
        name = self.ids.music.text
        global a
        if a == "play":
            self.ids.music.text = 'Music off'
            a= "stop"
             
        else:
            self.ids.music.text = 'Music on'
            a= "play"

class PloytestApp(App):
    def build(self):
        # Create the screen manager
        sm = ScreenManager()
        sm.add_widget(MenuScreen(name='menu'))
        sm.add_widget(Jeu(name='jeu'))
        sm.add_widget(RuleScreen(name='rules'))
        sm.add_widget(SettingsScreen(name='settings'))
        sm.transition = NoTransition()
        return sm

sound=SoundLoader.load('oui.wav')
def my_callback(dt):
    if a=="stop":
        sound.stop()
    elif a =="play":
        sound.play()
event = Clock.schedule_interval(my_callback, 1 / 30.)

def the_callback(dt):
    print("aaaaa")
    
if __name__ == '__main__':
    PloytestApp().run()
    App.stop(exit())


and my .kv filles

#: import Window kivy.core.window.Window 
#:  import Clock kivy.clock


    
<MenuScreen>:
    GridLayout:
        cols: 1
        Image:
            id: gif
            source: 'test.zip' 
            allow_stretch: True
            keep_aspect: False
            anim_loop: 0
            Label:
                pos: self.parent.pos
                size: self.parent.size
                text:"Connway's game of life"
                font_size: 60
                color: 0.5, 0.8, 1, 1
                
        GridLayout:
            cols: 1
            Button:
                text: 'Play'
                on_release:
                    root.manager.current = 'jeu'
            Button:
                text:  'How to Play'
                on_release:
                    root.manager.current = 'rules'
            Button:
                text: 'Goto settings'
                on_release: 
                    root.manager.current = 'settings'
            Button:
                text: 'Quit'
                on_release: app.stop() 

<Jeu>:  
    GridLayout:
            cols:1
            Label:
               ** #here is the grid of button**
                text: "here the grid of button"
        GridLayout:
            cols:4
            ToggleButton:
                id:start
                text: 'Start simulation'
                on_state:
                    if self.state == 'normal':\
                    print("aa")
                    root.test()
                    if self.state == 'normal':\
                    root.stop()
            Button:
                id:next
                text: 'Next Generation'
            Button:
                id:clear
                text: 'Clear'
                on_press:
                    start.state ='normal' if start.state == 'down' else 'normal'
            Button:
                text:"Back to menu"
                on_press:
                    start.state ='normal' if start.state == 'down' else 'normal'
                on_release: 
                    root.manager.current = 'menu'
        
<RuleScreen>:
    GridLayout:
        cols:1
        Image:
            source: 'rules.jpg'
        GridLayout:
            cols: 2
            Button:
                text: 'Setting'
                on_release:
                    root.manager.current = 'settings'
            Button:
                text: 'Back to menu'
                on_release:
                    root.manager.current = 'menu'

<SettingsScreen>:
    GridLayout:
        cols: 1
        size: root.width - 100, root.height -100
        Button:
            id: fullscreen
            text: "Fullscreen off"
            on_release:
                root.fullscreen()
        Button:
            id: music
            text: "Music on"
            on_release:
                root.music()
        Button:
            text: 'Back to menu'
            on_press:                
                root.manager.current = 'menu'

i try to put a for loop but with no sucess, i tried to change the class of "Jeu" from Screen to GridLayout it not allow to start the program. I just want a grid of toggle button 10x10 is a good start .

I m sorry for the level of english it s not my main language so there may be french in my code. Also i use thonny to code since i m lazy and it s the program school make us instal. Thanks in advance for the help.


Solution

  • You would want to use RecycleView with RecycleGridLayout, as shown in this post.

    file.py

    from kivy.app import App
    from kivy.uix.screenmanager import ScreenManager, Screen
    
    class Jeu(Screen):
        pass
    
    class PloytestApp(App):
    
        def build(self):
            sm = ScreenManager()
            sm.add_widget(Jeu(name="jeu"))
            return sm
    
    if __name__ == "__main__":
        PloytestApp().run()
    

    ploytest.kv

    <Jeu>:
        RecycleView:
            data: [{'text': str(x)} for x in range(10 * 10)]
            viewclass: 'ToggleButton'
    
            RecycleGridLayout:
                rows: 10
                cols: 10
                size_hint: 1, 1
                default_size_hint: 1, 1
    

    If you need to apply a custom text to each button, then you could use something like this

    #:set texts [...]
    
    <Jeu>:
        RecycleView:
            data: [{'text': texts[x]} for x in range(10 * 10)]
            viewclass: 'ToggleButton'
    
            RecycleGridLayout:
                rows: 10
                cols: 10
                size_hint: 1, 1
                default_size_hint: 1, 1
    

    The first line declares a list named texts, in which you can put your 100 different texts.

    Finally, if you want to add additional properties to each button, you can add as many as you want inside the data dictionary in the kv file. For example, if you want to also add some red color to the button's text:

    <Jeu>:
        RecycleView:
            data: [{'text': str(x), 'color': (1, 0, 0, 1)} for x in range(10 * 10)]
            viewclass: 'ToggleButton'
    
            RecycleGridLayout:
                rows: 10
                cols: 10
                size_hint: 1, 1
                default_size_hint: 1, 1
    

    EDIT

    <Jeu>:
        BoxLayout:
            orientation: 'vertical'
    
            RecycleView:
                data: [{'text': str(x)} for x in range(10 * 10)]
                viewclass: 'ToggleButton'
    
                RecycleGridLayout:
                    rows: 10
                    cols: 10
                    size_hint: 1, 1
                    default_size_hint: 1, 1
    
            GridLayout:
                size_hint: 1, 0.1
                cols:4
    
                ToggleButton:
                    text: 'Start simulation'
    
                Button:
                    text: 'Next Generation'
    
                Button:
                    text: 'Clear'
    
                Button:
                    text:"Back to menu"