Search code examples
pythonkivyscrollview

Kivy ScrollView with 3 ScrollView Layouts - Trying to create freeze pane like in Excel


I am using the Kivy Library in Python

I am trying to group 3 scroll layouts together. Basically, a side list, a header view and a main body window. The side list should only scroll up and down. The header should only scroll left and right and the main window can scroll on both axis. I have this much done but the information in the main window will be linked to that in both header and side list so having them scrolling independently won't work.

What I am aiming for is when the main window is scrolled, the x and y scroll values are passed to the side menu and header so that they all scroll together in the appropriate directions. I had a read through the scrollview code on github and just couldn't figure out what properties I could use to make to get this to work. I was thinking I could pass the scroll from one layout to an other!! Maybe too simple!!!

alternatively maybe i need to start with a GridLayout??

Thanks for any input

the code i have so far... the py file

    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    from kivy.config import Config
    from kivy.uix.stacklayout import StackLayout
    from kivy.uix.widget import Widget
    from kivy.uix.label import Label
    from datetime import datetime as dt
    from datetime import timedelta


    Config.set('graphics', 'width', '500')
    Config.set('graphics', 'height', '800')


    names = [str(x) for x in range (60)]


    end =dt.strptime((dt.today()+timedelta(days=1)).strftime("%d/%m/%Y")+ " "+ "00:01","%d/%m/%Y %H:%M" )
    result_time = "00:00"
    time =dt.strptime(dt.today().strftime("%d/%m/%Y")+ " "+ result_time,"%d/%m/%Y %H:%M" )
    segment = timedelta(minutes = 15)
    time_list = []

    while time<end:
        time_list.append(result_time)
        time += segment
        result_time = dt.strftime(time, "%H:%M")



    class TimeButton(Label):
        pass

    class BoxesLabel(Widget):
        pass

    class NameButton(Label):
        pass

    class Names(StackLayout):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            for x in names:
                btn = NameButton(text = x)
                self.add_widget(btn)

    class Times(StackLayout):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            for time in time_list:
                btn = TimeButton(text = time)
                self.add_widget(btn)


    class Boxes(StackLayout):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            for time in time_list:
                for name in names:
                    btn = BoxesLabel()
                    self.add_widget(btn)


    class MainWindow(BoxLayout):
        pass




    class TempApp(App):
        def build(self):
            return MainWindow()

    if __name__=="__main__":
        TempApp().run()



    

and the kv file

    <Layout>: #this just puts a box around all boxlayouts
        canvas.before:
            Color:
                rgba: 1,1,0,1
            Line:
                rectangle: (self.x, self.y, self.width, self.height)

    <NameButton>:
        size_hint_y: None
        size: dp(0),dp(50)

    <Names>:
        height: self.minimum_height
        padding: 10
        orientation: "lr-tb" 
        size_hint: 1, None
        size: 1, self.height

    <TimeButton>:
        size_hint: None, 1
        size: dp(50),0

    <Times>:
        width: dp(5000)
        orientation: "lr-tb"     
        size_hint: None, 1
        size: self.width, 1





    <BoxesLabel>:
        canvas.before:
            Color:
                rgba: 1,0,0,1
            Line:
                rectangle: (self.x, self.y, self.width, self.height)
        size_hint: None, None
        size: dp(50),dp(50)

    <Boxes>:
        size_hint: None, None
        width: dp(5000)
        height: self.minimum_height
        padding: 10
        orientation: "lr-tb"     



    <MainWindow>:
        orientation: "vertical"

        BoxLayout:  
            size_hint_y: None
            size_y: dp(150) 

            BoxLayout:
                size_hint_x: None
                size: dp(100),0

            ScrollView:
                BoxLayout:
                    width: dp(5000)#self.minimum_width     
                    size_hint: None, 1
                    size: self.width, 1
                    orientation: "vertical"
                    padding: dp(10)

                    BoxLayout:
                        Times:


        BoxLayout: 
            ScrollView:
                size_hint_x: None
                size: dp(100),0

                Names:

            ScrollView:

                Boxes:

Solution

  • So after 6 hours I finally got it, thanks to kivy synchronize each Scroll_y

    Here is the code I used, was just a case of binding the relevant scroll_x and scroll_y vaulues to each other scroll box!! No change to the PY file and just a few lines added to kv file!

    Here is updated KV file

        <Layout>: #this just puts a box around all boxlayouts
            canvas.before:
                Color:
                    rgba: 1,1,0,1
                Line:
                    rectangle: (self.x, self.y, self.width, self.height)
    
        <NameButton>:
            size_hint_y: None
            size: dp(0),dp(50)
    
        <Names>:
            height: self.minimum_height
            padding: 10
            orientation: "lr-tb" 
            size_hint: 1, None
            size: 1, self.height
    
        <TimeButton>:
            size_hint: None, 1
            size: dp(50),0
    
        <Times>:
            width: dp(5000)
            orientation: "lr-tb"     
            size_hint: None, 1
            size: self.width, 1
    
    
    
    
    
        <BoxesLabel>:
            canvas.before:
                Color:
                    rgba: 1,0,0,1
                Line:
                    rectangle: (self.x, self.y, self.width, self.height)
            size_hint: None, None
            size: dp(50),dp(50)
    
        <Boxes>:
            size_hint: None, None
            width: dp(5000)
            height: self.minimum_height
            padding: 10
            orientation: "lr-tb"     
    
    
    
        <MainWindow>:
    
            orientation: "vertical"
    
            BoxLayout:  
                size_hint_y: None
                size_y: dp(150) 
    
                BoxLayout:
                    size_hint_x: None
                    size: dp(100),0
    
                ScrollView:
                    id: _Header_Scroll
                    _Boxes_Scroll: _Boxes_Scroll
                    scroll_x: self._Boxes_Scroll.scroll_x
    
                    BoxLayout:
                        width: dp(5000)#self.minimum_width     
                        size_hint: None, 1
                        size: self.width, 1
                        orientation: "vertical"
                        padding: dp(10)
    
                        BoxLayout:
                            Times:
    
    
            BoxLayout: 
                ScrollView:
                    id: _Names_Scroll
                    _Boxes_Scroll: _Boxes_Scroll
                    scroll_y: self._Boxes_Scroll.scroll_y
    
                    size_hint_x: None
                    size: dp(100),0
    
                    Names:
    
                ScrollView:
                    id: _Boxes_Scroll
                    _Names_Scroll: _Names_Scroll
                    scroll_y: self._Names_Scroll.scroll_y
    
                    _Header_Scroll: _Header_Scroll
                    scroll_x: self._Header_Scroll.scroll_x
    
                    Boxes: