pythonkivyborderkivy-languagetabbed

Kivy: how to change the border of a TabbedPanel?


I'm struggling for hours now, just to be able to customize the style of my TabbedPanel in Kivy. Here is my code:

#: import Utils kivy.utils

BoxLayout:
    spacing: 0
    padding: 0
    canvas:
        Color:
            rgb: Utils.get_color_from_hex("#1b262d")[:3]
        Rectangle:
            size: self.size

    TabbedPanel:
        do_default_tab: False
        tab_width: self.size[0] / 2

        canvas:
            Color:
                rgb: Utils.get_color_from_hex("#00ff00")[:3]
            Rectangle:
                size: self.size

        TabbedPanelItem:
            background_color: Utils.get_color_from_hex("#1b262d")
            text: "PAST"
            background_down: ""
            background_normal: ""


            BoxLayout:
                orientation: "vertical"
                canvas:
                    Color:
                        rgb: Utils.get_color_from_hex("#1b262d")[:3]
                    Rectangle:
                        size: self.size
                        pos: self.pos

                BoxLayout:
                    padding: [10, 12, 10, 12]
                    spacing: 5
                    size_hint_y: 0.1
                    TextInput:
                        background_color: Utils.get_color_from_hex("#303E46")
                        foreground_color: [1, 1, 1, 1]
                        size_hint_x: 0.2
                        padding: [10, ( self.height - self.line_height ) / 2]
                        text: "DATES"
                    TextInput:
                        size_hint_x: 0.15
                        padding: [10, ( self.height - self.line_height ) / 2]
                        text: "TEST"
                    TextInput:
                        size_hint_x: 0.2
                        padding: [10, ( self.height - self.line_height ) / 2]
                        text: "CAT"
                    TextInput:
                        size_hint_x: 0.15
                        padding: [10, ( self.height - self.line_height ) / 2]
                        text: "SORT BY"
                    TextInput:
                        size_hint_x: 0.15
                        padding: [10, ( self.height - self.line_height ) / 2]
                        text: "SHOW ONLY"
                    TextInput:
                        size_hint_x: 0.15
                        padding: [10, ( self.height - self.line_height ) / 2]
                        text: "SEARCH"

                BoxLayout:
                    size_hint_y: 0.8
                    spacing: 10
                    padding: 10
                    orientation: "horizontal"
                    canvas:
                        Color:
                            rgb: Utils.get_color_from_hex("#303E46")[:3]
                        Rectangle:
                            size: self.size
                            pos: self.pos


                    Button:
                        size_hint_x: 0.7
                        text: "TEST"
                    Button:
                        size_hint_x: 0.3
                        text: "TESTS"

        TabbedPanelItem:
            background_color: Utils.get_color_from_hex("#303E46")
            text: "UPCOMING"
            background_down: ""
            background_normal: ""

here is the resulting window: resulting window

I actually highlighted in green the part I want to remove. I don't want this green part in the picture, that is to say I want my tab to be next to my content without this weird border.

Obviously If I don't force the canvas to be green I'll see something like this: I don't want this weird border

And so I see there is a gap between my TabbedPanelItem and my content and I don't know how to delete it. I've tried to force border to 0, strip_border to 0, change the height of my widget, force the background_image to "", etc but I am not able to achieve why I want.

Can an expert of Kivy help me out ?

Thank you in advance


Solution

  • It's more tricky that I suspected...

    Buttons are stored inside _tab_layout property of TabbedPanel. It's a GridLayout subclass and you can alter its padding property. Here's an example:

    from kivy.app import App
    from kivy.uix.floatlayout import FloatLayout
    from kivy.uix.gridlayout import GridLayout
    from kivy.lang import Builder
    
    Builder.load_string('''
    <StripLayoust>:
        canvas:
            Color:
                rgba: (0, 1, 0, 1) # green
            Rectangle:
                size: self.size
                pos: self.pos
    
    <MainClass>:
        TabbedPanel:
            id: panel
            do_default_tab: False
            TabbedPanelItem:
                text: "1"
                Widget:
                    canvas:
                        Color:
                            rgb: 0.1, 0.3, .02
                        Rectangle:
                            size: self.size
                            pos: self.pos
            TabbedPanelItem:
                text: "2"
                Widget:
                    canvas:
                        Color:
                            rgb: 0.7, 0.6, .02
                        Rectangle:
                            size: self.size
                            pos: self.pos
    ''')
    
    class MainClass(FloatLayout):
        def __init__(self, *args):
            super(MainClass, self).__init__(*args)
            self.ids["panel"]._tab_layout.padding = '2dp', '2dp', '2dp', '-2dp'
    
    class TestApp(App):
        def build(self):
            return MainClass()
    
    if __name__ == '__main__':
        TestApp().run()
    

    Note that to remove this border I had to set bottom padding to -2dp and not simply 0dp. Why? Well, as it turned out, every time the panel changes its update_tabs method is called and inside of it there's this cute line:

                tab_layout.height = (tab_height + tab_layout.padding[1] +
    tab_layout.padding[3] + dp(2))
    

    Adding dp(2) is hard-coded there so I need to use a negative value to counter that.

    I use underscore attribute here which is not a part of established public API so this behaviour might change in the future.