pBuch
pBuch

Reputation: 1001

Kivy TabbedPanel Autofocus

I have a Kivy application based on a TabbedPanel. Now I want to autofocus one of the TextInputs when I change to a tab.

When initializing the applications, this works:

class FocusedTextInput(TextInput):
    def on_parent(self, widget, parent):
        self.focus = True

But when changing to another tab and back to the first one, the FocusedTextInput is already on its parent so the callback isn't thrown. Whenever I want to handle other events (e.g. the click event of the TabbedPanelItem or the on_parent of it), the instance of the FocusedTextInput is None, even when I schedule a callback (e.g. 10s after) and the Input is visible and usable through other functions (e.g. focus_out handler of the input).

Is there any way to automatically focus one TextInput once the user changed tabs?

I look forward to your answers and hope for you kivy experts out there. ;-)


These parts of my application might be interesing for you: This class initializes the tabs (one tab for this example) and loads the content from the kv file.

class Applikation(App):
    bezahlungProp = ObjectProperty(None)
    #[...]

    def build(self):
        rootNode = TabbedPanel(do_default_tab=False)
        rootNode.bind(current_tab=self.tabChanged)

        bezahlungitem = TabbedPanelItem(text="Bezahlung")
        self.bezahlungitem = bezahlungitem
        self.bezahlung = Bezahlung()
        rootNode.add_widget(bezahlungitem)
        bezahlungitem.add_widget(self.bezahlung)
        self.bezahlungProp = ObjectProperty(self.bezahlung)
        self.bezahlung.add_widget(Builder.load_file("bezahlung.kv"))
        # [...]
        return rootNode
    def tabChanged(self, instance, value):
        Builder.sync()
        value.content.init()

This represents one tab:

class Bezahlung(BoxLayout):
   ticketIDInp = ObjectProperty(None)

   def on_parent(self, a, b):
        Clock.schedule_once(self.on_parent_callback,10)
   def on_parent_callback(self,b):
        #this throws an error -> self.ticketIDInp is None
        self.ticketIDInp.focus = True

   def init(self):
        #Application also fails here:
        self.ticketIDInp.focus = True

   def ticketIDInp_focus_out(self):
        #I can use self.ticketIDInp.text here without problems
        response = self.server.request("hookStatFromTicket",{"ticketID":self.ticketIDInp.text})
        [...]

Relevant part of the bezahlung.kv:

Bezahlung:
    ticketIDInp: ticketIDInp 
    BoxLayout:
        BoxLayout:
            FocusedTextInput:
                id: ticketIDInp
                on_text_validate: root.ticketIDInp_focus_out()

Upvotes: 0

Views: 587

Answers (1)

Yoav Glazner
Yoav Glazner

Reputation: 8066

One way to do what you want is to bind the current_tab property. Here is a working example (the 2nd Tab is the one with the wanted behavior)

from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.lang import Builder

Builder.load_string("""

<Test>:
    size_hint: .5, .5
    pos_hint: {'center_x': .5, 'center_y': .5}
    do_default_tab: False

    TabbedPanelItem:
        text: 'first tab'
        Label:
            text: 'First tab content area'
    TabbedPanelItem:
        id: tab2
        text: 'tab2'
        BoxLayout:
            Label:
                text: 'Second tab content area'
            TextInput:
                text: 'Button that does nothing'
                focus: root.current_tab == tab2   # <--- this is it! also can be changed to "== self.parent.parent"
""")

class Test(TabbedPanel):
    pass


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

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

Upvotes: 1

Related Questions