Есть ли способ иметь поле TextInput, которое выполняет автоматический поиск в списке адресов? - PullRequest
0 голосов
/ 17 января 2020

Я бы хотел, чтобы пользователь мог начинать вводить адрес в поле TextInput, а когда он начинает печатать, он просматривает список и выдает варианты соответствия. Это что-то, что можно сделать в kivy?

Я могу найти пример, если он недостаточно ясен, но они встречаются повсеместно на большинстве веб-сайтов, где вы должны указать адрес (например, адрес доставки)

Ответы [ 2 ]

0 голосов
/ 19 января 2020

Вот еще один подход, который использует TextInput с DropDown:

# -*- encoding: utf-8 -*-
"""
Chooser
=======

Uses TextInput with a DropDown to choose from a list of choices

The 'choicesfile' attribute can be used to specify a file of possible choices (one per line)
The 'choiceslist' attribute can be used to provide a list of choices

When typing in the TextInput, a DropDown will show the possible choices
and a suggestion will be shown in the TextInput for the first choice.
Hitting enter will select the suggested choice.

"""


from kivy.properties import ListProperty, StringProperty
from kivy.uix.button import Button
from kivy.uix.dropdown import DropDown
from kivy.uix.textinput import TextInput


class Chooser(TextInput):
    choicesfile = StringProperty()
    choiceslist = ListProperty([])

    def __init__(self, **kwargs):
        self.choicesfile = kwargs.pop('choicesfile', '')  # each line of file is one possible choice
        self.choiceslist = kwargs.pop('choiceslist', [])  # list of choices
        super(Chooser, self).__init__(**kwargs)
        self.multiline = False
        self.halign = 'left'
        self.bind(choicesfile=self.load_choices)
        self.bind(text=self.on_text)
        self.load_choices()
        self.dropdown = None

    def open_dropdown(self, *args):
        if self.dropdown:
            self.dropdown.open(self)

    def load_choices(self):
        if self.choicesfile:
            with open(self.choicesfile) as fd:
                for line in fd:
                    self.choiceslist.append(line.strip('\n'))
        self.values = []

    def keyboard_on_key_down(self, window, keycode, text, modifiers):
        if self.suggestion_text and keycode[0] == ord('\r'):  # enter selects current suggestion
            self.suggestion_text = ' '  # setting suggestion_text to '' screws everything
            self.text = self.values[0]
            if self.dropdown:
                self.dropdown.dismiss()
                self.dropdown = None
        else:
            super(Chooser, self).keyboard_on_key_down(window, keycode, text, modifiers)

    def on_text(self, chooser, text):
        if self.dropdown:
            self.dropdown.dismiss()
            self.dropdown = None
        if text == '':
            return
        values = []
        for addr in self.choiceslist:
            if addr.startswith(text):
                values.append(addr)
        self.values = values
        if len(values) > 0:
            if len(self.text) < len(self.values[0]):
                self.suggestion_text = self.values[0][len(self.text):]
            else:
                self.suggestion_text = ' '  # setting suggestion_text to '' screws everything
            self.dropdown = DropDown()
            for val in self.values:
                self.dropdown.add_widget(Button(text=val, size_hint_y=None, height=48, on_release=self.do_choose))
            self.dropdown.open(self)

    def do_choose(self, butt):
        self.text = butt.text
        if self.dropdown:
            self.dropdown.dismiss()
            self.dropdown = None

if __name__ == '__main__':
    from kivy.app import App
    from kivy.uix.relativelayout import RelativeLayout

    class TestApp(App):
        def build(self):
            layout = RelativeLayout()
            choices = ['Abba', 'dabba', 'doo']
            chooser = Chooser(choiceslist=choices, hint_text='Enter one of Fred\'s words', size_hint=(0.5,None), height=30, pos_hint={'center_x':0.5, 'center_y':0.5})
            layout.add_widget(chooser)
            return layout


    TestApp().run()
0 голосов
/ 18 января 2020

Вот начало другого подхода, который использует Spinner:

from kivy.app import App
from kivy.properties import StringProperty, ListProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.spinner import Spinner


class AddressChooser(FocusBehavior, Spinner):
    addressfile = StringProperty()
    addresslist = ListProperty([])

    def __init__(self, **kwargs):
        self.addressfile = kwargs.pop('addressfile', '')
        self.sync_height = True
        super(AddressChooser, self).__init__(**kwargs)
        self.modifiers = []
        self.bind(addressfile=self.load_addresses)
        self.load_addresses()

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

    def load_addresses(self):
        if self.addressfile:
            with open(self.addressfile) as fd:
                for line in fd:
                    self.addresslist.append(line)
        else:
            self.addresslist = []
        self.values = []
        if len(self.text) > 0:
            self.on_text(self, self.text)

    def on_text(self, chooser, text):
        values = []
        for addr in self.addresslist:
            if addr.startswith(text):
                values.append(addr)
        self.values = values
        self.is_open = True

    def keyboard_on_key_up(self, window, keycode):
        if keycode[0] == 304:
            self.modifiers.remove('shift')
        super(AddressChooser, self).keyboard_on_key_up(window, keycode)

    def keyboard_on_key_down(self, window, keycode, text, modifiers):
        if keycode[0] == 304:   # shift
            self.modifiers.append('shift')
        elif keycode[0] == 8 and len(self.text) > 0:   # backspace
            self.text = self.text[:-1]
        else:
            if 'shift' in self.modifiers:
                self.text += text.upper()
            else:
                self.text += text
        super(AddressChooser, self).keyboard_on_key_down(window, keycode, text, modifiers)


class TestApp(App):
    def build(self):
        layout = RelativeLayout()
        chooser = AddressChooser(addressfile='adresses.txt', size_hint=(0.5,None), height=50, pos_hint={'center_x':0.5, 'center_y':0.5})
        layout.add_widget(chooser)
        return layout

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