Search code examples
pythonkivyscrollview

ScrollView kivy


I have Python code:

class Screen3(Screen):
    def __init__(self, **kwargs):
        self.scv = ScrollView()
        self.bl_main = BoxLayout()
        self.bl_main.padding = [20, 20, 20, 20]
        self.bl_main.spacing = 50
        self.bl_main.orientation = 'vertical'
        super(Screen, self).__init__(**kwargs)

    def on_enter(self, *args):
        for i in [f'Button {i+1}' for i in range(20)]:
            b = Button()
            b.size_hint = None, None
            b.size = 350, 350
            b.text = i
            anch = AnchorLayout()
            anch.anchor_x = 'right'
            anch.add_widget(b)
            self.bl_main.add_widget(anch)
        self.scv.add_widget(self.bl_main)
        self.add_widget(self.scv)

And I have kivy code:

Screen3:
    name: 'screen3'
    BoxLayout:
        orientation: vertical
        AnchorLayout:
            anchor_x: 'center'
            anchor_y: 'top'
            MDToolbar:
                title: "History"
                left_action_items: [['menu', lambda x: nav_drawer.set_state()], ['skip-backward', lambda x: app.change_screen('main screen', screen_manager)]]
                elevation: 12

Here you can see my app.
https://pasteboard.co/J7KTdeR.jpg

  1. Why i can't click on my icon-buttons?
  2. Why my paddings and spacings don't consider and why ScrollView widget doesn't work?

How do I correct both of these points?

Please, help me.


Solution

  • Your icon-Buttons don't work because the ScrollView that you add in on_enter() has the default size_hint of (1,1), and thus fills the entire Screen3 (even though parts of the ScrollView are transparent). The ScrollView is grabbing the mouse clicks, so the icon-Buttons never see the mouse clicks.

    In a similar way, the BoxLayout (bl_main) also has the default size_hint, so its height will be the height of the ScrollView, and it will try to fit the 20 Buttons in that height. Each Button gets its share of the height, which is not enough, so they overlap.

    The fix is to build the ScrollView and BoxLayout in the kv to take advantage of the automatic bindings, and to set their sizes. Here is a version of your code that does that:

    from kivy.lang import Builder
    from kivy.uix.button import Button
    from kivy.uix.screenmanager import Screen, ScreenManager
    from kivymd.app import MDApp
    
    
    class Screen3(Screen):
        def on_enter(self, *args):
            for i in [f'Button {i+1}' for i in range(20)]:
                b = Button()
                b.size_hint = None, None
                b.size = 350, 350
                b.text = i
                # anch = AnchorLayout()
                # anch.anchor_x = 'right'
                # anch.add_widget(b)
                # self.ids.bl_main.add_widget(anch)
                self.ids.bl_main.add_widget(b)
    
    
    kv = '''
    Screen3:
        name: 'screen3'
        BoxLayout:
            orientation: 'vertical'
            size_hint_y: None
            height: toolbar.height
            pos_hint: {'center_x':0.5, 'top':1}
            # AnchorLayout:
            #     anchor_x: 'center'
            #     anchor_y: 'top'
            MDToolbar:
                id: toolbar
                title: "History"
                left_action_items: [['menu', lambda x: nav_drawer.set_state()], ['skip-backward', lambda x: app.change_screen('main screen', screen_manager)]]
                elevation: 12
        ScrollView:
            size_hint: (None, None)
            height: root.height - toolbar.height
            width: 390  # Button width plus BoxLayout padding
            pos_hint: {'right':1}
            BoxLayout:
                id: bl_main
                orientation: 'vertical'
                size_hint_y: None
                height: self.minimum_height
                padding: [20, 20, 20, 20]
                spacing: 50
    '''
    
    
    class TestApp(MDApp):
        def build(self):
            sm = ScreenManager()
            sm.add_widget(Builder.load_string(kv))
            return sm
    
    
    TestApp().run()
    

    Note the setting of sizes, positions, and the use of height: self.minimum_height for the BoxLayout. Refer to the ScrollView documentation for the reasoning behind this.

    I have also commented out your use of AnchorLayout, as it is superfluous.