Search code examples
pythonkivyfocus

Kivy for Python: Resetting focus after validation or locking focus to a text input field


I'm working on a To Do-App in Kivy: I got a text input field to type a task into. Afterwards, I confirm with Enter. Pressing Enter raises my "Confirm"-Function with Kivys built-in on-text-validate-Function. This "Confirm"-Function cleares the input field creates a button below, which shows the task. If the button is pressed, it deletes itself.

Here's my problem: After validating my input by pressing Enter, the text input field loses focus. I would have to click into the text input field in order to type a second task, which is quite inconvenient. I want the text input field to keep focus at all times.

I tried to reset the focus by including an text_input.focus = True in my confirm-function. This did not work.

I also tried using Kivys clock to call text_input.focus = True every 0.5 seconds. This did not work either.

Generally, I seem to be unable to set the focus via text_input.focus = True.

I'd love to find a solution to either

  1. reset the focus to my text input field when validating my input or
  2. lock the focus to my text input field.

I'll provide my code below. Thank you!

import kivy      

kivy.require('1.9.0')  

from kivy.app import App  
from kivy.uix.label import Label
from kivy.uix.button import Button  
from kivy.uix.textinput import TextInput 
from kivy.uix.gridlayout import GridLayout

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

# Create the App class 
class TutorialApp(App): 
      
    def build(self):
        def confirm(self):
            todo_element = Button(
                text = text_input.text,
                on_press = remove)
            grid.add_widget(todo_element)
            text_input.text = ""
            #text_input.focus = True

        def remove(self):
            self.parent.remove_widget(self)

        grid = GridLayout(
            cols = 1,
            row_default_height = 30,
            row_force_default = True)

        text_input = MyTextInput(
            text ="",
            multiline = False,
            on_text_validate = confirm)

        grid.add_widget(text_input)

        return grid
            
# Run the App 
if __name__ == "__main__": 
    TutorialApp().run() 

Solution

  • The is a property of TextInput that does what you want. See the documentation. The property is text_validate_unfocus. So you can change your Creation of the MyTextInput instance to use this property:

        text_input = MyTextInput(
            text ="",
            multiline = False,
            text_validate_unfocus = False,
            on_text_validate = confirm)