Noob Saibot
Noob Saibot

Reputation: 4749

Kivy: Is there a "BoundedString" property available for TextInputs?

Is there a way for TextInputs to receive a bounded string value (i.e., string of maximum length, x)? I tried investigating how to mixin AliasProperty in order to mimic BoundedNumericProperty, but can't find any Property class methods.

Upvotes: 3

Views: 1219

Answers (3)

Abhishek P
Abhishek P

Reputation: 189

There is simple problem with the code given above. you have to use NumericProperty.defaultvalue in order to use the code ( in the length comparison). Below is simple child class that can be used to create the classes for any size you deem fit.

class CustomInput(TextInput):

def  __init__(self , **kwargs):
    if "max_chars" in kwargs:
        self.max_chars = NumericProperty(int(kwargs["max_chars"]))
    super(CustomInput , self ).__init__(**kwargs)

def insert_text( self , substring , from_undo = False ):
    if not from_undo and ( len( self.text ) + len( substring ) > self.max_chars.defaultvalue ):
        return
    super( CustomInput , self).insert_text( substring , from_undo)

i pass max_chars as a keyword argument to the init. this works if i use just int for max_chars instead of NumericProperty

Upvotes: 1

qua-non
qua-non

Reputation: 4162

By the time on_text is called text is already changed in the textinput. You want to override insert_text to catch the text before it is inserted into the TextInput and thus before the text property is updated so as to restrict the entry to the TextInput.

Please don't bind/request the keyboard as the textinput does that for you and your handler will stop working after the Textinput is focused (TextInput would request the keyboard and in a single keyboard environment your handler will stop working).

Here is a sample code overriding insert_text to restrict text text entry to only numeric input.

class NumericInput(TextInput):

    def insert_text(self, substring, from_undo=False):
        if not from_undo:
            try:
                int(substring)
            except ValueError:
                return
        super(NumericInput, self).insert_text(substring, from_undo)

So For restricting the text to a certain length you could do the following::

class CustomInput(TextInput):

    max_chars = NumericProperty(10)

    def insert_text(self, substring, from_undo=False):
        if not from_undo and (len(self.text)+len(substring) > self.max_chars):
            return
        super(CustomInput, self).insert_text(substring, from_undo)

Upvotes: 7

toto_tico
toto_tico

Reputation: 19027

I think that the event on_text is triggered each time you modify the text. So you can override the method:

def on_text(self, instance, value):
    print('The widget', instance, 'have:', value)

    # validate here!!!

    # you might also want to call the parent.
    #super(ClassName, self).on_text(instance, value)

Or bind it:

def my_callback(instance, value):
    print('The widget', instance, 'have:', value)
    #validate here

textinput = TextInput()
textinput.bind(text=my_callback)

Be careful with the infinitive recursion. If you modify the text variable inside on_text or my_callback you might be triggering the event ago. I honestly don't remember but I think it does, so you need a flag such as validating before modifying the variable

You can also use still use on_focus so you check when the TextInput lost focus:

def on_focus(instance, value):
    if value:
        print('User focused', instance)
    else:
        print('User defocused', instance)

textinput = TextInput()
textinput.bind(focus=on_focus)

Finally, you can also bind the keyboard so you will guarantee access before the TextInput. I honestly don't know the order of execution but if you use on_text you might be deleting after the letter appearing on the screen which might be undesirable.

I think implementing your own BoundedStringProperty would be quite a work to achieve what you want. Here is the code of BoundedNumericProperty

Also, you shouldn't be trying to use an AliasProperty since you already got StringProperty that triggers the on_text event mentioned before.

Upvotes: 3

Related Questions