Search code examples
pythonpython-3.xkivyscrollviewerkivy-language

Why isn't the ScrollView working properly?


I basically have no clue on why the ScrollView isn't scrolling

Here is the python code:

from kivy.app import App
from kivy.config import Config
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty
from kivy.properties import NumericProperty
from kivy.properties import ListProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.screenmanager import *
from kivy.uix.scrollview import ScrollView


class ScrollButton(Button):
    pass

class DropperScrollView(ScrollView):
    layout=ObjectProperty()

class MainWindow(FloatLayout):
    mainbox=ObjectProperty()
    dropper=ObjectProperty()
    mainbutton=ObjectProperty()
    dropper_button_1=ObjectProperty()
    dropper_button_2=ObjectProperty()
    dropper_button_3=ObjectProperty()
    dropper_button_4=ObjectProperty()
    scroll_list=ObjectProperty()

    def open_dropper(self,dt):
        self.dropper.open(self.mainbutton)

    def btn_1(self,a):
        if self.scroll_list.layout.children==[]:
            btn_1=ScrollButton(text='Button 1')
            btn_2=ScrollButton(text='Button 2')
            self.scroll_list.layout.add_widget(btn_1)
            self.scroll_list.layout.add_widget(btn_2)


class BioWikiaApp(App):
    ratio=1/7
    window_width=360
    window_height=640
    squared_ratio=NumericProperty(ratio)
    squared_dropper_size_hint=ListProperty([ratio,ratio*9/16])
    squared_dropper_size=ListProperty([window_width*ratio,window_height*ratio*9/16])
    def build(self):
        Window.size=(self.window_width,self.window_height)
        Window.clearcolor=(155/255,220/255,160/255,1)
        return MainWindow()


if __name__=='__main__':
    app=BioWikiaApp()
    app.run()

And the kivy file:

#:import Clock kivy.clock.Clock
#:import App kivy.app.App
#:import Window kivy.core.window.Window
#:import NoTransition kivy.uix.screenmanager.NoTransition
<DropperScrollView>:
    layout:scroll_layout
    size_hint_x:app.squared_ratio
    pos_hint:{'x':app.ratio,'y':0}
    GridLayout:
        id:scroll_layout
        cols:1
        size_hint_y:None

<ScrollButton>:
    size_hint_y:None
    height:400

<MainWindow>:
    id:mainwindow
    mainbox:mainbox
    dropper:dropper
    dropper_button_1:dropper_button_1
    dropper_button_2:dropper_button_2
    dropper_button_3:dropper_button_3
    dropper_button_4:dropper_button_4
    mainbutton:mainbutton
    scroll_list:scroll_list
    BoxLayout:
        id:mainbox
        Label:
            text:'This will hold the title'
    Button:
        id:mainbutton
        text:'Home'
        size_hint:app.squared_dropper_size_hint[0],app.squared_dropper_size_hint[1]
        pos_hint:{'x':0,'y':1-app.squared_dropper_size_hint[1]}
        on_parent:
            dropper.dismiss()
            Clock.schedule_once(root.open_dropper,-1)
        on_release:dropper.open(self)
    DropDown:
        id:dropper
        dismiss_on_select:False
        on_select: mainbutton.text = '{}'.format(args[1])
        Button:
            id:dropper_button_1
            text:'1'
            size_hint_y:None
            height:mainbutton.height
            on_release:root.btn_1(self)
        Button:
            id:dropper_button_2
            text:'2'
            size_hint_y:None
            height:mainbutton.height
            on_release:root.btn_1(self)
        Button:
            id:dropper_button_3
            text:'3'
            size_hint_y:None
            height:mainbutton.height
            on_release:root.btn_1(self)
        Button:
            id:dropper_button_4
            text:'4'    
            size_hint_y:None
            height:mainbutton.height
            on_release:root.btn_1(self)
    DropperScrollView:
        id:scroll_list

Although what really matters for me in the moment is making this damned ScrollView scroll, feel free to correct me on anything else I might have done wrong (like making Drop_Down List a child of the mainwindow cause I couldn't make it work otherwise)

Many thanks in advance


Solution

  • Solution

    Please refer to the example for details.

    1. DropDown is a special widget just like Popup. Don't try to add it as a child to any other widget. If you do, DropDown will be handled like an ordinary widget and dropdown list will be opened i.e. won't be closed in the background. In kv file, create a dynamic class <CustomDropDown@DropDown>: and add widgets to it.
    2. Buttons in the ScrollView are bigger than the ScrollView because size_hint_y: None was not specified.
    3. Set the height to minimum height such that there is something to scroll.

    ScrollView » Managing the Content Size and Position

    layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
    # Make sure the height is such that there is something to scroll.
    layout.bind(minimum_height=layout.setter('height'))
    for i in range(100):
        btn = Button(text=str(i), size_hint_y=None, height=40)
        layout.add_widget(btn)
    root = ScrollView(size_hint=(1, None), size=(Window.width, Window.height))
    

    ScrollView » bar_width

    bar_width
    

    Width of the horizontal / vertical scroll bar. The width is interpreted as a height for the horizontal bar.

    bar_width is a NumericProperty and defaults to 2.

    Example

    main.py

    from kivy.app import App
    from kivy.core.window import Window
    from kivy.uix.floatlayout import FloatLayout
    from kivy.uix.button import Button
    from kivy.uix.scrollview import ScrollView
    from kivy.properties import ListProperty, NumericProperty, ObjectProperty
    
    
    class ScrollButton(Button):
        pass
    
    
    class DropperScrollView(ScrollView):
        layout = ObjectProperty(None)
    
    
    class MainWindow(FloatLayout):
        mainbutton = ObjectProperty(None)
        scroll_list = ObjectProperty(None)
    
        def btn_1(self):
            if not self.scroll_list.layout.children:    # empty list
                btn_1 = ScrollButton(text='Button 1')
                btn_2 = ScrollButton(text='Button 2')
                self.scroll_list.layout.add_widget(btn_1)
                self.scroll_list.layout.add_widget(btn_2)
    
    
    class BioWikiaApp(App):
        ratio = 1/7
        window_width = 360
        window_height = 640
        squared_ratio = NumericProperty(ratio)
        squared_dropper_size_hint = ListProperty([ratio, ratio*9/16])
        squared_dropper_size = ListProperty([window_width*ratio, window_height*ratio*9/16])
    
        def build(self):
            Window.size = (self.window_width, self.window_height)
            Window.clearcolor = (155/255, 220/255, 160/255, 1)
            return MainWindow()
    
    
    if __name__ == '__main__':
        BioWikiaApp().run()
    

    biowikia.kv

    #:kivy 1.11.0
    #:import Factory kivy.factory.Factory
    
    <DropDownButton@Button>:
        size_hint_y: None
        height: app.root.mainbutton.height
    
    
    <CustomDropDown@DropDown>:
        on_select: app.root.mainbutton.text = '{}'.format(args[1])
    
        DropDownButton:
            id: dropper_button_1
            text: '1'
            on_release:
                root.select(self.text)
                app.root.btn_1()
    
        DropDownButton:
            id: dropper_button_2
            text: '2'
            on_release:
                root.select(self.text)
                app.root.btn_1()
    
        DropDownButton:
            id: dropper_button_3
            text: '3'
            on_release:
                root.select(self.text)
                app.root.btn_1()
    
        DropDownButton:
            id: dropper_button_4
            text: '4'
            on_release:
                root.select(self.text)
                app.root.btn_1()
    
    
    <DropperScrollView>:
        layout: scroll_layout
        size_hint: (app.squared_ratio, None)
        pos_hint: {'x': app.ratio, 'y': 0}
    
        bar_width: 10
        bar_color: 0, 1, 0, 1   # green
        bar_inactive_color: 1, 0, 0, 1   # red
        effect_cls: "ScrollEffect"
        scroll_type: ['bars']
    
        GridLayout:
            id: scroll_layout
            cols: 1
            size_hint_y: None
            height: self.minimum_height
    
    <ScrollButton>:
        size_hint_y: None
        height: 400
    
    <MainWindow>:
        mainbox: mainbox
        mainbutton: mainbutton
        scroll_list: scroll_list
    
        BoxLayout:
            id: mainbox
    
            Label:
                text:'This will hold the title'
        Button:
            id: mainbutton
            text: 'Home'
            size_hint: app.squared_dropper_size_hint[0], app.squared_dropper_size_hint[1]
            pos_hint: {'x':0, 'y': 1 - app.squared_dropper_size_hint[1]}
            on_release: Factory.CustomDropDown().open(self)
    
        DropperScrollView:
            id:scroll_list
    

    Output

    Img01 Img02 Img03