Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make my horizontal scroll view in Kivy centered on the screen?

I'm trying to make a horizontal scroll view in Kivy (Python) which would display an image (buttons for now) that you can scroll through. I've been able to figure out how to do the horizontal scroll view, but I just can't seem to figure out what I'm doing wrong to center on the screen. Here is what I have so far:

import kivy
kivy.require('1.8.0')

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout

class MyGrid(GridLayout):
    def __init__(self, **kwargs):
        super(MyGrid, self).__init__(**kwargs)
        self.rows = 1
        self.spacing=50
        self.size_hint=(None, .5)
        self.bind(minimum_width=self.setter('width'))

class ScrollViewApp(App):
    def build(self):
        scroll = ScrollView( size_hint=(1,1), do_scroll_x=True, do_scroll_y=False )
        grid = MyGrid()
        for i in range(60):
            grid.add_widget(Button(text='#00' + str(i),size=(100,100), size_hint=(1,1)))
        scroll.add_widget(grid)
        return scroll

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

I looked through the documentation and I think it has something to do with pos_hint: https://kivy.org/doc/stable/api-kivy.uix.widget.html?highlight=pos_hint#kivy.uix.widget.Widget.pos_hint

I tried adding:

self.pos={'center_y':1}

in my MyGrid() class, but nothing is being changed. No matter what value is I put after center_y, my the ScrollView contained in the grid still appears at the top of the screen, rather than centered halfway down. I've also tried adjusting things in the ScrollViewApp() class too, using

scroll.pos={'center_y':1}

as well. I can't seem to figure out what I'm doing wrong. Does anyone have any ideas on what I'm not understanding here? I feel like I'm so close!!!

Edit:

I'm trying to have the buttons centered, but also be able to scroll by dragging the black space around the buttons. In the picture below, you can see there is a bunch of black space beneath the buttons. I can click a button or this black space and scroll horizontally. I just need this to happen with the buttons centered!

enter image description here

like image 461
nightmare637 Avatar asked Sep 19 '25 11:09

nightmare637


1 Answers

The layout is behaving as you told it to.
You have a ScrollView as a root widget, and inside it you put your Grid that has size_hint_y = 0.5.

It takes half of the parent widget height, that takes the full window height.
One way to center your Grid is to put some spacers over and under it, but this is not possible, since ScrollView accepts onle one widget as content.

So, one solution is to..

  • let the Grid have the full height of the ScrollView
  • add the ScrollView inside another Layout (e.g. a BoxLayout)
  • and finally, add two widgets to force the ScrollView in the center.
class MyGrid(GridLayout):
    def __init__(self, **kwargs):
        super(MyGrid, self).__init__(**kwargs)
        self.rows = 1
        self.spacing = 50
        self.size_hint = (None, 1)
        self.bind(minimum_width=self.setter('width'))


class ScrollViewApp(App):
    def build(self):
        base = BoxLayout(orientation="vertical", size_hint=(1, 1))
        base.add_widget(Widget(size_hint_y=.3))
        scroll = ScrollView(size_hint=(1, .4), do_scroll_x=True, do_scroll_y=False)
        grid = MyGrid()
        for i in range(60):
            grid.add_widget(
                Button(text='#00' + str(i), size=(100, 100), size_hint=(1, 1)))
        scroll.add_widget(grid)
        base.add_widget(scroll)
        base.add_widget(Widget(size_hint_y=.3))
        return base


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

Another approach would be to..

  • put the ScrollView inside a FloatLayout
  • and position it using pos_hint
class MyGrid(GridLayout):
    def __init__(self, **kwargs):
        super(MyGrid, self).__init__(**kwargs)
        self.rows = 1
        # self.spacing = 50
        self.size_hint = (None, 1)
        self.bind(minimum_width=self.setter('width'))


class ScrollViewApp(App):
    def build(self):
        base = FloatLayout(size_hint=(1, 1))
        scroll = ScrollView(size_hint=(1, .4), do_scroll_x=True, do_scroll_y=False,
                            pos_hint={"center_y": .5})
        grid = MyGrid()
        for i in range(60):
            grid.add_widget(
                Button(text='#00' + str(i), width=100, size_hint=(None, 1)))
        scroll.add_widget(grid)
        base.add_widget(scroll)
        return base


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

Edit:

OK. After the update of the question, this is a way to to center and use the black bars to scroll:

Builder.load_string("""
<BaseWidget>:
    ScrollView:
        do_scroll_y: False
        BoxLayout:
            orientation: "vertical"
            size_hint_x: None
            width: self.minimum_width
            Widget:
                size_hint_y: .3
            GridLayout:
                id: grid
                rows: 1
                size_hint_y: .4
                size_hint_x: None
                width: self.minimum_width
            Widget:
                size_hint_y: .3
""")


class BaseWidget(FloatLayout):
    pass


class ScrollViewApp(App):
    def build(self):
        base = BaseWidget()
        for i in range(60):
            base.ids.grid.add_widget(Button(text='#00' + str(i),
                                            width=100, size_hint_x=None))
        return base


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

It uses kv_lng to create the layout because I find it easier to the eye.
For a "Python only" code you can use this:

class MyGrid(GridLayout):
    def __init__(self, **kwargs):
        super(MyGrid, self).__init__(**kwargs)
        self.rows = 1
        self.size_hint = None, .4
        self.bind(minimum_width=self.setter('width'))


class MyBox(BoxLayout):
    def __init__(self, **kwargs):
        super(MyBox, self).__init__(**kwargs)
        self.orientation = "vertical"
        self.size_hint_x = None
        self.bind(minimum_width=self.setter('width'))


class ScrollViewApp(App):
    def build(self):
        base = FloatLayout()
        grid = MyGrid()
        box = MyBox()
        box.add_widget(Widget(size_hint_y=.3))
        box.add_widget(grid)
        box.add_widget(Widget(size_hint_y=.3))
        for i in range(60):
            grid.add_widget(Button(text='#00' + str(i), width=100, size_hint_x=None))
        scroll = ScrollView(do_scroll_y=False, pos_hint={"center_y": .5})
        scroll.add_widget(box)
        base.add_widget(scroll)
        return base


if __name__ == '__main__':
    ScrollViewApp().run()
like image 151
noEmbryo Avatar answered Sep 22 '25 10:09

noEmbryo