2

I am trying to validate a TextInput in Kivy before doing calculations on the value of the Input before Updating the calculated data to a ListView. But when I test the first TextInput value by printing it out there is nothing, no error and no result. I have referenced the on_press root.calvariable method AddKalibrasieForm Class in my Kivy file, but still nothing. Can someone please give me a clue to what I am doing incorrectly?

Edit: I have noticed what I did wrong: I imported TextInput without declaring the Class (it has been removed) and did not declare the val_lewerha TextInput object in the correct method (fixed it), so it prints to the console. My question has changed to can you validate an users Input on Input? Is this called on_focus? e.g. of what method I think should achieve the desired result:

def validate_input(self):
    if isinstance(self.textinput, (int, float)):
        accept self.textinput
    else:
        make self.textinput color red as incorrect data type

2nd Edit: I must have missed it, but another two Stack Overflow Q&A's got me to the correct answer, Stack_Overflow_Answer1; Stack_Overflow_Answer2. I also skimmed past the Kivy Documentation that showed an example of only allowing floating point numbers and one point in a TextInput on inserting text Kivy1.11.0_TextInput_Documentation. So I will be able to solve it. @eyllanesc: I only want to allow a user to insert floating point '0-9' in the TextInput, no strings. Thanks. How do I mark this as answered?

Here is my Python3 code as is:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty

class AddKalibrasieForm(BoxLayout):
    calculated_results = ObjectProperty()

    def convert_calvariables(self):
        val_lewerha = ObjectProperty()
        not_filled_in = ""
        flowha = float(self.val_lewerha.text)
        if flowha != not_filled_in and isinstance(flowha, (int, float)):
            print(format(self.val_lewerha.text))
        else:
            print("Error")

class CalibrationApp(App):
    pass

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

Here is a part of my Kivy file: calibration.kv

AddKalibrasieForm:

<AddKalibrasieForm>:
    orientation: "vertical"
    val_lewerha: volha_box
    calculated_results: calculated_results_table
    BoxLayout:
        height: "40dp"
        size_hint_y: None
        Label:
            text: "Lewering per ha"
            size_hint_x: 25
        TextInput:
            id: volha_box #TextInput object name
            size_hint_x: 50
        Label:
            text: "liter"
            size_hint_x: 25
            text_size: self.size
            halign: "left"
    BoxLayout:
        height: "60dp"
        size_hint_y: None
        Label:
            size_hint_x: 35
        Button:
            text: "Bereken"
            size_hint_x: 30
            on_press: root.convert_calvariables() #method called on_press
        Label:
            size_hint_x: 35
    ListView:
        id: calculated_results_table
        table_items: []
Hmerman6006
  • 1,622
  • 1
  • 20
  • 45
  • you could explain what would be the validation behavior, for example let's say that in the TextInput this is the value "12" and now the user presses "s" then that should be shown in the TextInput – eyllanesc Aug 04 '18 at 08:08
  • please improve your indentation in your .kv – eyllanesc Aug 04 '18 at 08:13
  • please answer here, not in your post, have you found your solution? – eyllanesc Aug 04 '18 at 14:33
  • Yes, I added a line in my kivy file "input_filter = 'float'" as given in the documentation and it solved it. Thank you. – Hmerman6006 Aug 06 '18 at 14:05

1 Answers1

9

Please refer to explanations and example for details.

TextInput - input_filter

Use input_filter: 'float'. With input_filter, you don't have to check for 'init' or 'float' in your method.

input_filter

input_filter

Filters the input according to the specified mode, if not None. If None, no filtering is applied.

input_filter is an ObjectProperty and defaults to None. Can be one of None, ‘int’ (string), or ‘float’ (string), or a callable. If it is ‘int’, it will only accept numbers. If it is ‘float’ it will also accept a single period. Finally, if it is a callable it will be called with two parameters; the string to be added and a bool indicating whether the string is a result of undo (True). The callable should return a new substring that will be used instead.

kv file

Two Roots Defined

In your kv file, you have a root rule, AddKalibrasieForm: and class rule, <AddKalibrasieForm>: defined for the same root widget. Since you are not using def build() method then remove class rule, <AddKalibrasieForm>: in the kv file.

TextInput - volha_box

Add the following:

  • multiline: False # disable multiline
  • hint_text: "Slegs nommers" # Numbers only
  • input_filter: "float"

Python Code

class AddKalibrasieForm(BoxLayout):
    calculated_results = ObjectProperty(None)
    val_lewerha = ObjectProperty(None)

    def convert_calvariables(self):
        if len(self.val_lewerha.text) > 0:   # if text is not empty
            print(format(self.val_lewerha.text))
        else:
            print("Error: Empty string")

Declaration of a Property

To declare properties, you must declare them at the class level.

Example

main.py

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty


class AddKalibrasieForm(BoxLayout):
    calculated_results = ObjectProperty(None)
    val_lewerha = ObjectProperty(None)

    def convert_calvariables(self):
        if len(self.val_lewerha.text) > 0:   # if text is not empty
            print(format(self.val_lewerha.text))
        else:
            print("Error: Empty string")


class CalibrationApp(App):
    pass


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

calibration.kv

#:kivy 1.11.0

AddKalibrasieForm:  # root rule
    orientation: "vertical"
    val_lewerha: volha_box
    calculated_results: calculated_results_table

    BoxLayout:
        height: "40dp"
        size_hint_y: None

        Label:
            text: "Lewering per ha"
            size_hint_x: 25

        TextInput:
            id: volha_box   # TextInput object name
            size_hint_x: 50
            hint_text: "Slegs nommers"
            multiline: False
            input_filter: "float"

        Label:
            text: "liter"
            size_hint_x: 25
            text_size: self.size
            halign: "left"

    BoxLayout:
        height: "60dp"
        size_hint_y: None

        Label:
            size_hint_x: 35

        Button:
            text: "Bereken"
            size_hint_x: 30
            on_press: root.convert_calvariables()   # method called on_press

        Label:
            size_hint_x: 35

    ListView:
        id: calculated_results_table
        table_items: []

Output

Img01

ikolim
  • 15,721
  • 2
  • 19
  • 29
  • Your answer is better than my single line and great explanation. Still learning alot. Thanks. – Hmerman6006 Aug 06 '18 at 14:07
  • Please remember to vote on or accept the answer. *Click the green outlined checkmark to the left of the answer that solved your problem.* – ikolim Aug 06 '18 at 14:21
  • Green. I know this is off topic, I have six more textinputs that I use to do calculations with. Do I use the ListProperty to get a list of these objects so I can loop through them and check if not empty? Also I notice that textinputs always return a string and I have to convert them to int or float. Is this the default textinput behaviour or is there a property that can do this? – Hmerman6006 Aug 06 '18 at 14:36
  • Use `for child in reversed(self.container.children):`. Please check out my solution at [TextInputs Validation](https://stackoverflow.com/questions/50153595/python-add-validation-in-form/50160963#50160963) – ikolim Aug 06 '18 at 14:47
  • Thanks again ikolim for a very helpful comment. – Hmerman6006 Aug 06 '18 at 14:53