Kivy — предельные значения для InputText

Я пытаюсь сделать ввод текста, который принимает только значения с плавающей запятой. Кроме того, введенное значение должно находиться между двумя значениями.

Я создал класс, содержащий метод проверки. Если значение не находится между двумя значениями, отображается всплывающее окно.

Но у меня есть проблема. Метод вызывается только тогда, когда пользователь нажимает «Enter». Я пробовал вызывать метод при изменении текста, но это раздражает пользователя, потому что всплывающее окно появляется все время, пока пользователь вводит данные.

Есть ли другой подход, чтобы сделать что-то подобное?

Файл Python:

class BoundedInput(BoxLayout):
    value = NumericProperty()

    def validate(self, min_value, max_value):
        status = min_value <= self.value <= max_value
        if not status:
            message = f'Value must be between {min_value} and {max_value}'
            popup = Popup(title='Warning', content=Label(text=message),
                            size_hint=(None, None), size=(300, 200))
            popup.open()

Kv-файл:

<NumericInput@TextInput>:
    input_filter: 'float'
    multiline: False

<BoundedInput>:
    orientation: 'horizontal'
    Label:
        text: 'Value'
    NumericInput:
        text: str(root.value)
        on_text_validate:
            root.value = float(self.text)
            root.validate(5, 100)

person Eduardo    schedule 19.01.2018    source источник


Ответы (2)


Подходящим подходом может быть фильтрация в дополнение к плаванию this также в пределах диапазона, для которого мы создаем класс, который наследует TextInput, и перезаписываем метод insert_text:

from kivy.app import App
from kivy.base import Builder
from kivy.properties import NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput


Builder.load_string("""
<BoundedLayout>:
    orientation: 'horizontal'
    Label:
        text: 'Value'
    NumericInput:
        min_value : 5
        max_value : 100
        hint_text : 'Enter values between {} and {}'.format(self.min_value, self.max_value)
""")

class NumericInput(TextInput):
    min_value = NumericProperty()
    max_value = NumericProperty()
    def __init__(self, *args, **kwargs):
        TextInput.__init__(self, *args, **kwargs)
        self.input_filter = 'float'
        self.multiline = False

    def insert_text(self, string, from_undo=False):
        new_text = self.text + string
        if new_text != "":
            if self.min_value <= float(new_text) <= self.max_value:
                TextInput.insert_text(self, string, from_undo=from_undo)

class BoundedLayout(BoxLayout):
    pass

class MyApp(App):
    def build(self):
        return BoundedLayout()

if __name__ == '__main__':
    MyApp().run()
person eyllanesc    schedule 21.01.2018
comment
Это хороший подход. Единственное, пользователи не знают, почему они не могут ввести некоторые значения. Я добавил 'hint_text' в input_text, чтобы уведомить пользователя о минимальном и максимальном значениях. Спасибо! - person Eduardo; 22.01.2018
comment
@ Эдуардо Конечно, это дополняет мое решение. - person eyllanesc; 22.01.2018
comment
@Eduardo Эдуардо Я уже добавил это, если мой ответ помог вам, вы можете отметить его как правильный. :D - person eyllanesc; 22.01.2018
comment
Я нашел проблему, я не могу набрать 100 например с самого начала. Я буду исследовать, как я могу это решить. - person Eduardo; 22.01.2018
comment
Поправьте меня, если я ошибаюсь, но разве эта проверка не предполагает, что подстрока добавляется? Что, если новый текст вставить в середину существующего текста, т.е. 3,90 -> 39,90 проверит, находится ли 3,909 в диапазоне... - person Daniel B.; 24.11.2018

Вы можете использовать Bubble и оставить его зависшим, пока ввод неправильно.
Вы даже можете отредактировать метку, чтобы указать, что не так.
Или изменить цвет текста, если он проверен или нет.
Я сделал пример с обоими реализованными.

from kivy.app import App
from kivy.uix.textinput import TextInput
from kivy.uix.bubble import Bubble
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import BooleanProperty

KV = """

<ValidateLabel>:
    size_hint: (None, None)
    size: (280, 60)
    Label:
        id: label
        text: "Must be a float"


<MyInput>:
    foreground_color: (0,1,0,1) if root.validated else (1,0,0,1)


FloatInput:

"""


class MyInput(TextInput):
    validated = BooleanProperty(False)


class FloatInput(FloatLayout):
    bubble_showed = True

    def __init__(self, **kwargs):
        super(FloatInput, self).__init__(**kwargs)
        self.input = MyInput()
        self.input.bind(text=self.validate)
        self.add_widget(self.input)
        self.bubble = ValidateLabel()
        self.add_widget(self.bubble)

    def validate(self, input, value, min_value=15., max_value=25.):
        self.bubble.ids.label.text = "Number must be between {} and {}".format(min_value, max_value)
        try:
            print(min_value, max_value)
            status = float(min_value) <= float(value) <= float(max_value)
        except Exception as e:
            status = False
            self.bubble.ids.label.text = "Input must be a number"

        if not status:
            if not self.bubble_showed:
                self.input.validated = False
                self.add_widget(self.bubble)
                self.bubble_showed = True
        else:
            print("bubble removed")
            self.input.validated = True
            self.remove_widget(self.bubble)
            self.bubble_showed = False


class ValidateLabel(Bubble):
    validated = False


class TestApp(App):

    def build(self):
        return Builder.load_string(KV)


TestApp().run()

Выход:

Число меньше или больше: Не проверено

Номер в порядке: Проверено

Входное значение не является числом: Непроверенный ввод текста

person el3ien    schedule 21.01.2018
comment
Это хороший подход. Пользователь своевременно уведомлен. Я попробую, и я вернусь с комментариями. - person Eduardo; 22.01.2018
comment
@ Эдуардо, да, это как минимум два способа, которые, на мой взгляд, хорошо сочетаются друг с другом. Зеленый цвет указывает на то, что все в порядке, тогда пузырь не нужен. Удачи. - person el3ien; 23.01.2018