Search code examples
pythonpython-3.xkivy

Why does ScrollView from Kivy-framework not scroll data on a frame?


Here is a code written on Python3 Kivy:

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView

class TableLayout(GridLayout):
    def __init__(self, **kwargs):
        super(TableLayout, self).__init__(**kwargs)
        self.cols = 3  # Set the number of columns in the table
        self.row_default_height = 50  # Set the fixed height between rows
        self.spacing = 30
        self.bind(minimum_height=self.setter('height'))

        # Create the headers
        self.add_widget(Label(text='Checkboxes'))
        self.add_widget(Label(text='Column 2'))
        self.add_widget(Label(text='Column 3'))

    def add_row(self, checkbox_state, column2_text, column3_text):
        checkbox = CheckBox(active=checkbox_state)
        self.add_widget(checkbox)
        self.add_widget(Label(text=column2_text))
        self.add_widget(Label(text=column3_text))

class MyApp(App):
    def build(self):
        scrollview = ScrollView()
        table_layout = TableLayout()
        boo = lambda b: True if b == 'True' else False
        # Read the lines from the text file
        with open('data.txt', 'r') as file:
            line = file.readline()
            while line:
                data = line.split(';')
                table_layout.add_row(boo(data[0].strip()), data[1].strip(), data[2].strip())
                line = file.readline()
        
        scrollview.add_widget(table_layout)
        return scrollview

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

And the data.txt-file as well:

True; Row 1; Data 1
False; Row 2; Data 2
True; Row 3; Data 3
True; Row 4; Data 3
False; Row 5; Data 3
True; Row 6; Data 3
False; Row 7; Data 3
True; Row 8; Data 3
True; Row 9; Data 3
False; Row 10; Data 3
True; Row 11; Data 3
True; Row 12; Data 3
True; Row 13; Data 3
True; Row 14; Data 3
True; Row 15; Data 3
True; Row 16; Data 3
True; Row 17; Data 3
True; Row 18; Data 3
True; Row 19; Data 3
True; Row 20; Data 3
True; Row 21; Data 3
True; Row 22; Data 3
True; Row 23; Data 3
True; Row 24; Data 3
True; Row 25; Data 3

The code runs successfully, but a problem is to scroll the data received from the data.txt file. I can't get any way to scroll it with the mouse wheel or a finger moving (if use it as a mobile application). Is there any way to make it?

I try to consider the code below:


from kivy.app import App
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label

class ScrollableTable(ScrollView):
    def __init__(self, **kwargs):
        super(ScrollableTable, self).__init__(**kwargs)
        self.grid = GridLayout(cols=3, spacing=30, size_hint=(None, None))
        self.grid.bind(minimum_height=self.grid.setter('height'))
        self.grid.row_default_height = 50
        self.add_widget(self.grid)
        
        for i in range(100):
            self.grid.add_widget(Label(text=f'Row {i+1}, Col 1'))
            self.grid.add_widget(Label(text=f'Row {i+1}, Col 2'))
            self.grid.add_widget(Label(text=f'Row {i+1}, Col 3'))

class MyApp(App):
    def build(self):
        return ScrollableTable()

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

This code tries to scroll data but the an app generated by the code is illegible. Is there any ideas to do next?


Solution

  • There is no scrolling because there is nothing to scroll, the size of the GridLayout and the ScrollView is the same since size_hint_y is 1 (so the size of the GridLayout adapts to the size of the parent, the ScrollView).

    You must set the size_hint_y to None (disable it) or set size_hint_min to enable scrolling.

    from kivy.app import App
    from kivy.uix.gridlayout import GridLayout
    from kivy.uix.checkbox import CheckBox
    from kivy.uix.label import Label
    from kivy.uix.scrollview import ScrollView
    
    
    
    class TableLayout(GridLayout):
        def __init__(self, **kwargs):
            super(TableLayout, self).__init__(**kwargs)
            self.cols = 3  # Set the number of columns in the table
            self.row_default_height = 50  # Set the fixed height between rows
            self.spacing = 30
            self.bind(minimum_height=self.setter('height'))
            self.size_hint_y = None
    
            # Create the headers
            self.add_widget(Label(text='Checkboxes'))
            self.add_widget(Label(text='Column 2'))
            self.add_widget(Label(text='Column 3'))
    
        def add_row(self, checkbox_state, column2_text, column3_text):
            checkbox = CheckBox(active=checkbox_state)
            self.add_widget(checkbox)
            self.add_widget(Label(text=column2_text))
            self.add_widget(Label(text=column3_text))
    
    class MyApp(App):
        def build(self):
            scrollview = ScrollView()
            table_layout = TableLayout()
    
            with open('data.txt', 'r') as file:
                for line in file:
                    state, col2, col3 = line.strip().split(";")
                    table_layout.add_row(state == "True", col2, col3)
            
            scrollview.add_widget(table_layout)
            return scrollview
    
    if __name__ == '__main__':
        MyApp().run()
    

    As for the second code, you need to set the width of the widget somehow, for example by setting a default width of the columns:

    class ScrollableTable(ScrollView):
        def __init__(self, **kwargs):
            super(ScrollableTable, self).__init__(**kwargs)
            self.grid = GridLayout(cols=3, spacing=30, size_hint=(None, None))
            self.grid.bind(minimum_height=self.grid.setter('height'))
            self.grid.bind(minimum_width=self.grid.setter('width'))
            self.grid.row_default_height = 50
            self.grid.col_default_width = 200
            self.add_widget(self.grid)