Search code examples
pythonbuttonkivyscrollviewboxlayout

Kivy \\ How to tie a button to the bottom of the boxlayout


from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
from kivy.effects.scroll import ScrollEffect
from kivy.uix.widget import Widget
from kivy.uix.button import Button


class BSGameMain(BoxLayout):
    blmain = BoxLayout(orientation = 'vertical') # MainBoxLayout init

    scrlFBtns = ScrollView(effect_cls = 'ScrollEffect')

    blbtns = BoxLayout(
        orientation = 'vertical',
        size_hint_y = None
        ) # BoxLayout for buttons

    blbtns.bind(minimum_height = blbtns.setter('height'))
    scrlFBtns.add_widget(blbtns)

    for i in range (2):
        blbtns.add_widget(Button(
            text='asd',
            size_hint_y = None,
            height = 40
            ))

    lblmain = Label(text = 'asd')
    blmain.add_widget(lblmain)
    blmain.add_widget(scrlFBtns)


class BSApp(App):
    def build(self):
        game = BSGameMain()
        return game.blmain

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

It is necessary to make the buttons appear from below, and not from the middle, taking into account the scrollview. I just can't make him do it.

Screenshot


Solution

  • Please keep in mind that BoxLayouts override modifications to positioning, as they automatically position their children. This makes them pretty self-sufficient but a little stubborn to work with.

    Like you said, if there's only a couple buttons, it sticks to the middle. The scrollview works, but since it's a child of a boxlayout, it can only stretch as far as what the boxlayout says it can, which is the bottom half of the window. Also, since the boxlayout for the buttons adds children top-down, this is why your buttons appear in the middle. In reality, it's adding buttons to the top of the bottom half of the window.

    You have specified boxlayouts where boxlayouts are not necessary. One thing you might want is to position your scrollview at will, depending on the number of buttons in the scrollview. This will require an if statement and an integer.

    My changes:

    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    from kivy.uix.label import Label
    from kivy.core.window import Window
    from kivy.uix.scrollview import ScrollView
    from kivy.effects.scroll import ScrollEffect
    from kivy.uix.widget import Widget
    from kivy.uix.button import Button
    
    class BSGameMain(): #No longer a boxlayout.
        scroll_height = 0;
        blmain = Widget() #No longer a boxlayout. Fills the window.
    
        blbtns = BoxLayout(
            orientation = 'vertical',
            size_hint = (1, None),
            ) # BoxLayout for buttons
    
        blbtns.bind(minimum_height = blbtns.setter('height'))
    
        for i in range (20):     #number of buttons printed
            blbtns.add_widget(Button(
                text='asd',
                size_hint_y = None,
                height = 40
                ))
            if (scroll_height < (Window.height / 2)):
                scroll_height = scroll_height + 40      #This measures how much space we need for the scrollview. Make sure it matches button height!
    
        scrlFBtns = ScrollView(effect_cls = 'ScrollEffect', pos = (0, 0), size = (Window.width, scroll_height)) 
        #The pos of 0,0 ensures scrlFBtns stays at the bottom. Place at negative coordinates if you want it to extend off-screen.
        scrlFBtns.add_widget(blbtns)
        lblmain = Label(text = 'asd', halign = 'center', y = (Window.height * 0.75), width = Window.width, color = (1,1,1,1))
    
        blmain.add_widget(lblmain)
        blmain.add_widget(scrlFBtns)
    
    class BSApp(App):
        def build(self):
            game = BSGameMain()
            return game.blmain
    
    if __name__ == "__main__":
        BSApp().run()
    

    Results:

    One Button

    ,

    Three Buttons

    ,

    Twenty Buttons

    Hopefully this is along the lines of what you're looking for!