Search code examples
pythonkivy

Separate login screen from Screenmanager due to TabbedPanel


My Python app uses the screen manager to control my tabbed screens ('Main', 'First', 'Second'). I would like to add a login screen which shall not contain any tab. When I start the app the login screen appears for a fraction of second and is skipped over. Instead, the 'main' screen shows up. Without the TabbedPanel structure the 'login' screen is not skipped. So the 'login' screen created by the screenmanager whithout a TappedPanel seems to be the cause.

How can I seperate the 'login' screen from the screen manager or prevent it from getting skipped while keeping the TabbedPanel for all the other screens?

main.py:

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition 
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.floatlayout import FloatLayout
from kivy.clock import Clock

class TabbedTest(TabbedPanel):
    pass

class LoginScreen(Screen):
    pass

class MainScreen(Screen):
    def on_enter(self, *args):
        tab= self.ids.tabbedpanel
        home_tabX = self.ids.home_tab
        Clock.schedule_once(lambda *args: tab.switch_to(home_tabX))
    #pass

class Firstscreen(Screen):
    def on_enter(self, *args):
        tab= self.ids.tabbedpanel
        first_tabX = self.ids.first_tab
        Clock.schedule_once(lambda *args: tab.switch_to(first_tabX))

class Secondscreen(Screen):
    def on_enter(self, *args):
        tab= self.ids.tabbedpanel
        second_tabX = self.ids.second_tab
        Clock.schedule_once(lambda *args: tab.switch_to(second_tabX))

class TabTest_with_Screenmanager_V2(App):

    def build(self):
        sm = ScreenManager(size_hint_y=0.99, 
        pos_hint={'y': 0},transition=NoTransition())
        sm.add_widget(LoginScreen(name='login'))
        sm.add_widget(MainScreen(name='main'))
        sm.add_widget(Firstscreen(name='first'))
        sm.add_widget(Secondscreen(name='second'))
        root.add_widget(sm)

        return root

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

TabTest_with_Screenmanager_V2.kv:

<LoginScreen>:
    id: login
    Label:
        text: "Welcome"

<MainScreen>:
    id: main
    TabbedPanel:
        id: tabbedpanel
        do_default_tab: False
        TabbedPanelItem:
            id: home_tab
            text:"Main"

            BoxLayout:
                Label:
                    text:'Main'

        TabbedPanelItem:
            id: first_tab
            text:"First"  
            on_release: root.manager.current= 'first'



        TabbedPanelItem:
            id: second_tab
            text:"Second" 
            on_release:root.manager.current= 'second'


<Firstscreen>:
    id: first
    TabbedPanel:
        id: tabbedpanel
        do_default_tab: False
        TabbedPanelItem:
            id: home_tab
            text:"Main"
            on_state: if self.state == "down":root.manager.current= 'main'
        TabbedPanelItem:
            id: first_tab
            text:"First"
            BoxLayout:
                Label:
                    text:"first"

        TabbedPanelItem:
            id: second_tab
            text:"Second"
            on_state: if self.state == "down":root.manager.current= 'second'

<Secondscreen>:
    id: second
    TabbedPanel:
        id: tabbedpanel
        do_default_tab: False
        TabbedPanelItem:
            id: home_tab
            text:"Main"
            on_state: if self.state == "down":root.manager.current= 'main'
        TabbedPanelItem:
            id: first_tab
            text:"First"
            on_state: if self.state == "down":root.manager.current= 'first'
        TabbedPanelItem:
            id: second_tab
            text:"Second"
            BoxLayout:
                Label:
                    text:'second'

Solution

  • The problem is your use of state in the TabbedPanelItem. In a TabbedPanel, one of the TabbedPanelItems will be the current tab, and that TabbedPanelItem will get its state set to down. Then your on_state will get triggered and the current Screen will get changed. The fix is to replace your on_state lines in the kv with something like on_release. For example, change:

    on_state: if self.state == "down":root.manager.current= 'main'
    

    to:

    on_release: root.manager.current= 'main'