Martin
Martin

Reputation: 123

Python Kivy TabbedPanel - setting custom tab widths

Thanks for years of unknowingly helping me!! I've used this site so much but this is the first time that I'm actually going to have to post a question to get the info I need, which is amazing.

I've recently started learning Python (& Kivy) so I'm still a beginner. I'm using:

[INFO   ] [Kivy        ] v1.10.0
[INFO   ] [Python      ] v3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 16:07:46) [MSC v.1900 32 bit (Intel)]

I'm trying to resize the tabs(TabbedPanelItem) in a TabbedPanel so that they have adequate horizontal size, to allow for the text. There's another similar question here which has been answered with a solution. I've found this solution to work for me too, but only provided that I don't use a screen and put the Tabbed Panel inside anything else.

As soon as I change the structure so that the Tabbed Panel is nested, the solution no longer works.

Here is some example code which I took from the solution but modified it so that the Tabbed Panel isn't the root:

from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.lang import Builder

Builder.load_string("""

<Test2>:
    GridLayout:
        cols:1

        GridLayout:
            rows:1
            Label:
                text:'Does it show all 4 tabs?'
        GridLayout:
            rows:1
            TestForTabbedPanel

<CustomWidthTabb@TabbedPanelItem>
    width: self.texture_size[0]
    padding: 10, 0
    size_hint_x: None

<TestForTabbedPanel>:
    size_hint: 1,1
    do_default_tab: False
    tab_width: None

    CustomWidthTabb:
        text: "This is a Long Tab"
        Label:
            text: 'First tab content area'

    CustomWidthTabb:
        text: "This is a Long Tab"
        Label:
            text: 'Second tab content area'

    CustomWidthTabb:
        text: "Short Tab"     
        Label:
            text: 'Third tab content area'

    CustomWidthTabb:
        text: "Short Tab#2"   
        Label:
            text: 'Fourth tab content area'

""")

class Test2(Screen):
    pass

class TestForTabbedPanel(TabbedPanel):
    def __init__(self, *args, **kwargs):
        super(TestForTabbedPanel, self).__init__(*args, **kwargs)
        Clock.schedule_once(self.on_tab_width, 0.1)

class TabbedPanelApp(App):
    def build(self):
        return Test2()


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

ResultExampleImage

Compared to this, the solution provided in the other thread without nesting the tabbed panel works; it shows all the tabs and they have been sized dynamically:

from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.lang import Builder

Builder.load_string("""

<CustomWidthTabb@TabbedPanelItem>
    width: self.texture_size[0]
    padding: 10, 0
    size_hint_x: None

<Test>:
    size_hint: 1,1
    do_default_tab: False
    tab_width: None

    CustomWidthTabb:
        text: "This is a Long Tab"
        Label:
            text: 'First tab content area'

    CustomWidthTabb:
        text: "This is a Long Tab"
        Label:
            text: 'Second tab content area'

    CustomWidthTabb:
        text: "Short Tab"     
        Label:
            text: 'Third tab content area'

    CustomWidthTabb:
        text: "Short Tab#2"   
        Label:
            text: 'Fourth tab content area'

""")



class Test(TabbedPanel):
    def __init__(self, *args, **kwargs):
        super(Test, self).__init__(*args, **kwargs)
        Clock.schedule_once(self.on_tab_width, 0.1)

class TabbedPanelApp(App):
    def build(self):
        return Test()


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

How can I write the code, so that the TabbedPanel is nested inside a screen or another widget, but shows all the tabs with their adequate widths? What basics am I not understanding here?

Upvotes: 1

Views: 2197

Answers (1)

ikolim
ikolim

Reputation: 16031

Solution

Please refer to the example for details.

kv file

Add id for TestForTabbedPanel:

    GridLayout:
        rows:1
        TestForTabbedPanel:
            id: tp

Python code

  1. Move the __init__() method from class TestForTabbedPanel to class Test2
  2. Replace super(TestForTabbedPanel, self) with super(Test2, self)
  3. Replace self.on_tab_width with self.ids.tp.on_tab_width
  4. Add pass to class *TestForTabbedPanel

class Test2(Screen):
    def __init__(self, *args, **kwargs):
        super(Test2, self).__init__(*args, **kwargs)
        Clock.schedule_once(self.ids.tp.on_tab_width, 0.1)


class TestForTabbedPanel(TabbedPanel):
    pass

Example

from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.lang import Builder

Builder.load_string("""

<Test2>:
    GridLayout:
        cols:1

        GridLayout:
            rows:1
            Label:
                text:'Does it show all 4 tabs?'
        GridLayout:
            rows:1
            TestForTabbedPanel:
                id: tp

<CustomWidthTabb@TabbedPanelItem>
    width: self.texture_size[0]
    padding: 10, 0
    size_hint_x: None

<TestForTabbedPanel>:
    size_hint: 1,1
    do_default_tab: False
    tab_width: None

    CustomWidthTabb:
        text: "This is a Long Tab"
        Label:
            text: 'First tab content area'

    CustomWidthTabb:
        text: "This is a Long Tab"
        Label:
            text: 'Second tab content area'

    CustomWidthTabb:
        text: "Short Tab"     
        Label:
            text: 'Third tab content area'

    CustomWidthTabb:
        text: "Short Tab#2"   
        Label:
            text: 'Fourth tab content area'

""")


class Test2(Screen):
    def __init__(self, *args, **kwargs):
        super(Test2, self).__init__(*args, **kwargs)
        Clock.schedule_once(self.ids.tp.on_tab_width, 0.1)


class TestForTabbedPanel(TabbedPanel):
    pass


class TabbedPanelApp(App):
    def build(self):
        return Test2()


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

Output

Img01 - All tabs displayed

Upvotes: 2

Related Questions