How to add Scroll View to screen kivy

1,567 views
Skip to first unread message

Mittu Muppavaram

unread,
Sep 16, 2020, 7:15:10 AM9/16/20
to Kivy users support
I tried adding scrollview to my screen but it dosent work

please help me

thank you 

exp.py

Elliot Garbus

unread,
Sep 16, 2020, 10:46:44 AM9/16/20
to kivy-...@googlegroups.com

In your code you are putting an unsized screen in a scrollview.

The scrollview requires a sized object.  In the example below, a BoxLayout is in the scrollview.  It is sized:

        BoxLayout:
            orientation: 'vertical'
            id: sv_box
            size_hint_y: None
            height: self.minimum_height


And the objects in the scrollview also have a fixed size:

<InfoLine>:
    size_hint_y: None
    height: 48

    Label:
        text: root.label_text
    Button:
        text: root.button_text
        on_release: print(f'Button: {self.text} pressed')

 

Here is an example:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty

kv =
"""
<InfoLine>:
    size_hint_y: None
    height: 48
    Label:
        text: root.label_text
    Button:
        text: root.button_text
        on_release: print(f'Button: {self.text} pressed')
   
BoxLayout:
    orientation: 'vertical'
    Label:
        text: 'BoxLayout in a ScrollView'
        size_hint_y: None
        height: 48
    ScrollView:
       do_scroll_x: False
        do_scroll_y: True
        scroll_type:['bars', 'content']
        bar_width: 20
        BoxLayout:
            orientation: 'vertical'
            id: sv_box
            size_hint_y: None
            height: self.minimum_height
            InfoLine:
            InfoLine:
                label_text: 'Test'
                button_text: 'Initialized in kv'
              
"""


class InfoLine(BoxLayout):
    label_text = StringProperty(
'default')
    button_text = StringProperty(
'default')


class ScrollBoxApp(App):
   
def build(self):
       
return Builder.load_string(kv)

   
def on_start(self):
       
for i in range(100):
           
self.root.ids.sv_box.add_widget(InfoLine(label_text=f'Label {i}', button_text=f'Button {i}'))


ScrollBoxApp().run()

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/c7fed98c-3bff-46a2-8208-c0575884d410n%40googlegroups.com.

 

Mittu Muppavaram

unread,
Sep 16, 2020, 10:53:10 AM9/16/20
to kivy-...@googlegroups.com

Mittu Muppavaram

unread,
Sep 17, 2020, 9:33:55 AM9/17/20
to kivy-...@googlegroups.com
I tried with your example and I added scrollview but all the widgets are in same row I tried to align them they don't show any effect 
please help me
exp.py

Elliot Garbus

unread,
Sep 17, 2020, 10:40:34 AM9/17/20
to kivy-...@googlegroups.com

I modified your example code below.  Here is a summary of the key changes I made to get the ScrollView to work.

  1. The height of the item you are going to scroll needs to be set.  You had set the hint to None, but not set a height.
  2. A ScrollView can only directly contain one widget.  If you need to display multiple widget like do here, use Layout to hold the multiple widgets.  In this example of vertically scrolling items, I used a vertical BoxLayout.
  3. You must set the size of the item you are going to scroll.  Think about it this way.  You are creating a small window or peephole into a larger view.  The ScrollView needs to  know the size of the larger item so it can control the amount to scroll.  I a case where the size is going to be variable, you can have the layout calculate the size for you.  In this example, the size of the vertical BoxLayout is set as:

height: self.minimum_height

The attribute self.minimum_height is calculated by the layout, based on the number of widgets and the size of the widgets

  1. In the TestScrollView class I used on_kv_post() to create additional widgets.  On_kv_post is a kivy event that fires after the kv code has been processed.  This means the id’s are valid.  I used this to add 100 InfoLines to the  BoxLayout.  The size of the BoxLayout needs to be larger that the scroll view to see the scroll.

 

I also simplified the info line code, added a label like the one you were creating in the init to the Kv code, and created a new kivy property button_text to put a name on the buttons.

 

 

 

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty

kv =
"""
<InfoLine>:
    size_hint_y: None 
    height: 50      # see comment 1 above
    Label:
        text: 'state'
        color: 78 / 255.0, 77 / 255.0, 253 / 255.0, 1

    Button:
        text: root.button_text
        on_release: print(f'Button: {self.text} pressed')
    Label:
        text: "Custom color"
        color: 0, 0, 1, 1
        
TestScrollView:

    do_scroll_x: False
    do_scroll_y: True
    scroll_type:['bars', 'content']
    bar_width: 20
    BoxLayout:            # see comment 2 above
        id: box
        orientation: 'vertical'
        size_hint_y: None
        height: self.minimum_height    # see comment 3 above
        InfoLine:
        InfoLine:
            button_text: 'from kv'
"""


class InfoLine(BoxLayout):
    button_text = StringProperty(
'default value here')


class TestScrollView(ScrollView):
   
def on_kv_post(self, base_widget):          # comment 4
        box =
self.ids.box
       
for i in range(100):
            w = InfoLine(
button_text=f'Hello {i}')
            box.add_widget(w)


class ScrollBoxApp(App):

   
def build(self):
       
return
Builder.load_string(kv)


ScrollBoxApp().run()

exp (1).zip

Mittu Muppavaram

unread,
Sep 17, 2020, 10:53:45 AM9/17/20
to kivy-...@googlegroups.com
Thanks a lot Ill figure it

Mittu Muppavaram

unread,
Sep 18, 2020, 12:06:18 AM9/18/20
to kivy-...@googlegroups.com
Following your example I am able to work with scroll view but I need to position widgets randomly and then have scrolling for them

I tried using 
in main.py self.ids.container_y.add_widget(Button(text=sa),pos_hint={'x':.2, 'y':.2})
It did not give me the results
Please help me Thank you
main.py
main.kv
scroll.png

Elliot Garbus

unread,
Sep 18, 2020, 5:00:33 PM9/18/20
to kivy-...@googlegroups.com

Here is a version that puts the buttons in random x positions for the vertical scroll.

The key issue is that a BoxLayout does not honor position hints.  I put a button in a RelativeLayout, a FloatLayout would also work.

main.zip

Mittu Muppavaram

unread,
Sep 19, 2020, 2:45:02 AM9/19/20
to kivy-...@googlegroups.com
I tried to do so by following your instructions but I made it in only one class but unable to position widgets randomly
am getting scroll any way

Thank you

main.py
main.kv

Elliot Garbus

unread,
Sep 19, 2020, 10:57:38 AM9/19/20
to kivy-...@googlegroups.com

Lets look closer at the 2 examples:

 

Here is some of the KV code from your latest example:

<MainWid>:
   
FloatLayout:
       
ScrollView:
           
do_scroll_x: False
           
do_scroll_y: True
           
GridLayout:
               
orientation: 'vertical'
               
id: container_x
               
size_hint_y: None
                
cols: 5
               
row_default_height: root.height * 0.2
               
height: self.minimum_height

 

And the relevant py code:

class MainWid(FloatLayout):
   
def on_kv_post(self, base_widget):
        s =
"Boton: %s"

       
for i in range(30):
            sa = s % (i)
           
self.ids.container_x.add_widget(Button(text=sa,pos_hint= {'x': random() * .8, 'y': 1},size_hint =(.3, .2),
                   
pos =(300, 200)))

 

There are a few thing going on here.  Most important you are putting a Button in a GridLayout.  These is only one object in the grid.  The row height is set in kv.  The size hint is ignored so the Button fills the box.  You have defined both a position and a position hint, but both are ignored.  The Button fills the slot in the grid.

 

You could reduce the size of the button, but the pos_hint would be ignored.  You would end up with a grid of buttons a different widths.

 

 

To achieve what put the button in a RelativeLayout, and then put the RelativeLayout into the Grid.  The RelativeLayout honors the position hint and size hint of its children.

 

 

 

In the code below notice that NarrowButton is a RelativeLayout, with a Button in it. The Relative Layout honors the position hint.  The same code is also attached.

Mastering the layouts takes some time – but they are a very powerful tool.

 

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.relativelayout import RelativeLayout
from kivy.properties import StringProperty


kv =
"""
#:import random random.random
<NarrowButton>:
    Button:
        pos_hint: {'x': random() * .7}
        size_hint_x: None
        width: 70
        text: root.text
        on_release:
            print(f'{self.text} pos:{self.pos} size: {self.size}')
       
BoxLayout:

    ScrollView:
        do_scroll_x: False
        do_scroll_y: True
        GridLayout:
            id: container_y
            size_hint_y: None
            cols: 5
            row_default_height: root.height * 0.2
            height: self.minimum_height
"""


class NarrowButton(RelativeLayout):
    text = StringProperty()


class NarrowTestApp(App):
   
def build(self):
       
return Builder.load_string(kv)

   
def on_start(self):
       
for i in range(100):
           
self.root.ids.container_y.add_widget(NarrowButton(text=f'B {i}'))


NarrowTestApp().run()
pos_test.zip

Mittu Muppavaram

unread,
Sep 20, 2020, 9:46:07 AM9/20/20
to kivy-...@googlegroups.com
Thanks @Elliot for the help I really  getting to know how to work with layouts 

Reply all
Reply to author
Forward
0 new messages