Kivy: Clearing Text Input with 'on focus' or 'on_touch_down'

Question:

I want to clear a TextInput‘s text: when I click on it.
Sample Code:

from kivy.app import App
from kivy.lang import Builder

kv_string = """
ScreenManager:
    id: manager
    Screen:
        BoxLayout:
            orientation: 'vertical'
            Button:
                text: 'Why does it clear multiple inputs? And why do they get cleared after touch_up?'
            TextInput:
                text: 'Write Your Name'
                on_touch_down:
                    self.text = ''

            TextInput:
                text: 'Write Your Last Name'
                on_focus:
                    self.text = ''

            TextInput:
                text: 'Write Your Phone Number'
                on_touch_down:
                    self.text = ''
"""

class MyApp(App):

    def build(self):
        root_widget = Builder.load_string(kv_string)
        return root_widget

if __name__ == "__main__":
    MyApp().run()

Neither on_touch_down: or on_focus erases JUST the text input that is currently focused. Instead, both get cleared when I touch anywhere on the screen. I would want them cleared individually once the cursor is on a text input. I also tried on_cursor but that didn’t work either. What am I missing? Thank you in advance!

Asked By: Petar Luketina

||

Answers:

The on_touch_down event is received by all the widgets until one returns True telling the event-loop that it is using it and thus not send it to other widgets as indicated by the docs:

on_touch_down(touch) Added in 1.0.0

Receive a touch down event.

Parameters:

touch: MotionEvent class Touch received.

The touch is in parent coordinates. See relativelayout for a discussion on coordinate
systems.

Returns:

bool If True, the dispatching of the touch event will stop.
If False, the event will continue to be dispatched to the rest of the
widget tree.

The classic use of on_touch_down is in python since kv language is limited in the overwriting of methods:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.textinput import TextInput

class MyTextInput(TextInput):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            self.text = ""
            return True
        return super(MyTextInput, self).on_touch_down(touch)

kv_string = """
ScreenManager:
    id: manager
    Screen:
        BoxLayout:
            orientation: 'vertical'
            Button:
                text: 'Why does it clear multiple inputs? And why do they get cleared after touch_up?'
            MyTextInput:
                text: 'Write Your Name'
            MyTextInput:
                text: 'Write Your Last Name'  
            MyTextInput:
                text: 'Write Your Phone Number'
"""

class MyApp(App):
    def build(self):
        root_widget = Builder.load_string(kv_string)
        return root_widget

if __name__ == "__main__":
    MyApp().run()

Or something equivalent in .kv but the devestaja is that you can not return True.

kv_string = """
ScreenManager:
    id: manager
    Screen:
        BoxLayout:
            orientation: 'vertical'
            Button:
                text: 'Why does it clear multiple inputs? And why do they get cleared after touch_up?'
            TextInput:
                text: 'Write Your Name'
                on_touch_down: if self.collide_point(*args[1].pos): self.text = ""
            TextInput:
                text: 'Write Your Last Name'
                on_touch_down: if self.collide_point(*args[1].pos): self.text = ""
            TextInput:
                text: 'Write Your Phone Number'
                on_touch_down: if self.collide_point(*args[1].pos): self.text = ""
"""

So you should use on_focus which is an event associated to FocusBehavior that overwrites on_touch_down verifying using self.collide_point(*touch.pos).

from kivy.app import App
from kivy.lang import Builder

kv_string = """
ScreenManager:
    id: manager
    Screen:
        BoxLayout:
            orientation: 'vertical'
            Button:
                text: 'Why does it clear multiple inputs? And why do they get cleared after touch_up?'
            TextInput:
                text: 'Write Your Name'
                on_focus: self.text = ""
            TextInput:
                text: 'Write Your Last Name'
                on_focus: self.text = ""
            TextInput:
                text: 'Write Your Phone Number'
                on_focus: self.text = ""
"""

class MyApp(App):
    def build(self):
        root_widget = Builder.load_string(kv_string)
        return root_widget

if __name__ == "__main__":
    MyApp().run()
Answered By: eyllanesc

All you need to do is to just add this:

on_focus: self.text = '' if args[1] else self.text

on_focus is a function that gets called when the TextInput is selected or unselected, and the function gives you two arguments instance which is the thing got selected or unselected and value which is if that instance got selected or unselected, these two arguments get put in a list called args, and since we’re doing this in the widget itself in the kv file we don’t have to worry about instance, so we check if the value is True, and if it is that means that the TextInput got clicked, so we clear it, otherwise we set it to itself.

So this is how the script would look like:

from kivy.app import App
from kivy.lang import Builder

kv_string = """
ScreenManager:
    id: manager
    Screen:
        BoxLayout:
            orientation: 'vertical'
            Button:
                text: 'Why does it clear multiple inputs? And why do they get cleared after touch_up?'
            TextInput:
                text: 'Write Your Name'
                on_focus: self.text = '' if args[1] else self.text
            TextInput:
                text: 'Write Your Last Name'
                on_focus: self.text = '' if args[1] else self.text
            TextInput:
                text: 'Write Your Phone Number'
                on_focus: self.text = '' if args[1] else self.text
"""

class MyApp(App):
    def build(self):
        root_widget = Builder.load_string(kv_string)
        return root_widget

if __name__ == "__main__":
    MyApp().run()
Answered By: ZiyadCodes
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.