【问题标题】:how can i create a autocomplete textinput in kivy如何在 kivy 中创建自动完成文本输入
【发布时间】:2020-05-05 17:03:25
【问题描述】:

这是我的 .py 文件,我需要创建一个自动完成文本输入最小化这是python文件

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.dropdown import DropDown
from kivy.uix.scrollview import ScrollView
from kivy.lang import Builder
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.properties import NumericProperty,ListProperty, BooleanProperty, ObjectProperty
from kivy.uix.textinput import TextInput
import sqlite3
from kivy.uix.button import Button
from collections import OrderedDict

class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                                  RecycleBoxLayout):
''' Adds selection and focus behaviour to the view. '''


class SelectableLabel(RecycleDataViewBehavior, Label):
''' Add selection support to the Label '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
    ''' Catch and handle the view changes '''
       self.index = index
       return super(SelectableLabel, self).refresh_view_attrs(
        rv, index, data)

    def on_touch_down(self, touch):
    ''' Add selection on touch down '''
        if super(SelectableLabel, self).on_touch_down(touch):

           return True
        if self.collide_point(*touch.pos) and self.selectable:
           return self.parent.select_with_touch(self.index, touch)

   def apply_selection(self, rv, index, is_selected):
    ''' Respond to the selection of items in the view. '''
       self.selected = is_selected




class ListcreationWindow(BoxLayout):

    code_inp = ObjectProperty()
    flt_list = ObjectProperty()
    word_list = ListProperty()
    def __init__(self, **kwargs):
        super(ListcreationWindow, self).__init__(**kwargs)
        self.cart = []
        self.qty = []
        self.total = 0.00




class MyLayout(BoxLayout):
   code_inp = ObjectProperty()
   rv = ObjectProperty()
   def __init__(self, **kwargs):
       super(MyLayout, self).__init__(**kwargs)

class MyTextInput(TextInput):
   code_inp = ObjectProperty()
   flt_list = ObjectProperty()
   word_list = ListProperty()
# this is the variable storing the number to which the look-up will start
   starting_no = NumericProperty(3)
   suggestion_text = ''


   def __init__(self, **kwargs):
       super(MyTextInput, self).__init__(**kwargs)
   def on_text(self, instance, value):
    # find all the occurrence of the word

       matches = [self.word_list[i] for i in range(len(self.word_list)) if
       self.word_list[i][:self.starting_no] ==  value[:self.starting_no]]

       display_data = []
       for i in matches:
           display_data.append({'text': i})
    #ensure the size is okay
       if len(matches) <= 10:
           self.parent.height = (50 + (len(matches) * 20))
       else:
           self.parent.height = 240

   def keyboard_on_key_down(self, window, keycode, text, modifiers):
       if self.suggestion_text and keycode[1] == 'tab':
           self.insert_text(self.suggestion_text + ' ')
           return True
       return super(MyTextInput, self).keyboard_on_key_down(window, keycode, text, modifiers)

class RV(DropDown):

    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        notes = ['Features', 'Suggestions', 'Abreviations', 'Miscellaneous']
        for note in notes:
           btn = Button(text='%r' % note, size_hint_y=None, height=30)
           btn.bind(on_release=lambda btn: self.select(btn.text))
           self.add_widget(btn)
        mainbutton = MyTextInput()
        mainbutton.bind(on_text=self.open)
        self.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))




 class ListcreationApp(App):
    def build(self):
        return ListcreationWindow()

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

这是我的 .kv 文件,用于创建 RV 小部件在此处创建的 UI

<SelectableLabel>:
# Draw a background to indicate selection
    color: 0,0,0,1
    canvas.before:
       Color:
           rgba: (0, 0, 1, 5) if self.selected else (1, 1, 1, 1)
       Rectangle:
           pos: self.pos
           size: self.size
<MyTextInput>:
   readonly: False
   multiline: False
<RV>:

   bar_width: 1
   bar_color: 1, 0, 0, 1   # red
   bar_inactive_color: 0, 0, 1, 1   # blue
   viewclass: 'SelectableLabel'
   SelectableRecycleBoxLayout:
       default_size: dp(50), dp(30)
       default_size_hint: 1, None
       size_hint_y: None
       height: self.minimum_height
       orientation: 'vertical'
       multiselect: False
       touch_multiselect: True


<FlatButton@ButtonBehavior+Label>:
    font_size: 14
<ListcreationWindow>:
    id:main_win
    orientation:'vertical'
    pos: self.pos
    size: self.size
    canvas.before:
        Color:
           rgba:(1,1,1,1)
        Rectangle:
           size:self.size
           pos:self.pos
   BoxLayout:
       id:header
       size_hint_y:None
       canvas.before:
           Color:
               rgba:(.06, .45, .45, 1)
           Rectangle:
               size:self.size
               pos:self.pos
       Label:
           text: "Nadeem POS system"
           size_hint_x: .9
           bold: True
           color:(1,1,1,1)
       FlatButton:
           id:loggedin_user
           text:'nadeem'
           color:(1,1,1,1)
   BoxLayout:
       id:current
       size_hint_y:None
       height:50
       canvas.before:
           Color:
               rgba:(.06, .45, .45, 1)
           Rectangle:
               size:self.size
               pos:self.pos
       Button:
           text:'Current Item'
           background_normal:''
           background_color:(.06, .32 , .32, 1)
           size_hint_x: .4

       Button:
           id:cur_product
           text:'Default Product'
           background_normal:''
           background_color:(.06, .4 , .4, 1)
       Button:
           id:cur_price
           text:'0.00'
           background_normal:''
           background_color:(.06, .65 , .65, 1)
           size_hint_x: .2
    BoxLayout:
        padding:10
    BoxLayout:
        id: product_details
        orientation: "vertical"
        size_hint_x: .8
        spacing:10
        BoxLayout:
            id:product_labels
            size_hint_y:None
            height:40
            canvas.before:
                Color:
                    rgba:(.06,.45,.45, 1)
                Rectangle:
                    size:self.size
                    pos:self.pos
            FlatButton:
                text:'Qty'
                size_hint_x: .1
            FlatButton:
                text:'Product Code'
                size_hint_x: .3
            FlatButton:
                text:'Product Name'
                size_hint_x: .2
            FlatButton:
                text:'Price'
                size_hint_x: .1
        BoxLayout:
            id:product_inputs
            size_hint_y:None
            height: 30
            spacing:5
            TextInput:
                id:qty_inp
                size_hint_x:.1
            MyLayout:
                orientation: 'vertical'
                spacing: 2
                code_inp: code_inp
                MyTextInput:
                    id: code_inp
                    size_hint_x:1
                    multiline:False
                    size_hint_y:1
                    on_text_validate:root.update_purchases()
                RV:
                    id:rv
                    size_hint_x:1
            TextInput:
                id:disc_inp
                size_hint_x:.2
            TextInput:
                id:price_inp
                size_hint_x:.1
        BoxLayout:
            id:add_to_cart
            orientation:"vertical"
            BoxLayout:
                size_hint_y:None
                height:30
                canvas.before:
                    Color:
                        rgba:(.06,.45,.45,1)
                    Rectangle:
                        size:self.size
                        pos:self.pos
                Label:
                    text:'Code'
                    size_hint_x:.2
                Label:
                    text:'Product name'
                    size_hint_x:.3
                Label:
                    text:'Qty'
                    size_hint_x:.1
                Label:
                    text:'Price'
                    size_hint_x:.1
            GridLayout:
                id: products
                cols: 1
    BoxLayout:
        id:preview
        orientation:'vertical'
        size_hint_x:.2

        TextInput:
            id:receipt_preview
            readonly:True
            text:"\t\t\t\tThe Collector\n\t\t\t\t123 Main St\n\t\t\t\tKnowhere, Space\n      \n\t\t\t\tTel:(555)-123-456\n\t\t\t\tReceipt No:\n\t\t\t\t Gate:\n\n"

        Button:
            id:button_pro
            text:'Process'
            size:75,40
            size_hint: None,None
BoxLayout:
    id:footer
    size_hint_y:None
    height:30
    canvas.before:
        Color:
            rgba:(.06,.47,.47,1)
        Rectangle:
            pos:self.pos
            size:self.size
    Label:
        text:'maintained by nadeem'

【问题讨论】:

  • 请编辑您的帖子以更正python代码和kv文件中的缩进。
  • 另外,请简化,这样我们就不需要您的数据库来运行它。我想我要的是minimal reproducible example。
  • 缩进没有问题,但 Recyclerview 或 RV 类也是一个下拉列表,它不会向下,而是向上并最小化文本输入
  • 我的代码有缩进
  • 现在编辑代码,删除数据库部分

标签: python python-3.x kivy desktop-application


【解决方案1】:

这是DropDown 的破解版本,可让您指定是否希望DropDown 始终低于它所附加的Widget。

class CustomDropDown(DropDown):
    force_below = BooleanProperty(False)  # if True, DropDown will be positioned below attached to Widget
    def __init__(self, **kwargs):
        super(CustomDropDown, self).__init__(**kwargs)
        self.do_not_reposition = False  # flag used to avoid repositioning recursion

    def _reposition(self, *largs):
        if self.do_not_reposition:
            return
        super(CustomDropDown, self)._reposition(*largs)
        if self.force_below:
            self.make_drop_below()

    def make_drop_below(self):
        self.do_not_reposition = True  # avoids recursion triggered by the changes below
        if self.attach_to is not None:
            wx, wy = self.to_window(*self.attach_to.pos)
            self.height = wy  # height of DropDown will fill window below attached to Widget
            self.top = wy  # top of DropDown will be at bottom of attached to Widget
        self.do_not_reposition = False  # now turn auto repositioning back on

要使用它,您只需致电CustomDropDown(force_below=True)。当然,如果Widget下附Window下方的空间太小,这将无法使用。更通用的方法是允许指定低于、高于或正常的定位选择。

这可以在你的MyTextInput 类中使用:

class MyTextInput(TextInput):
    code_inp = ObjectProperty()
    flt_list = ObjectProperty()
    word_list = ListProperty()
    # this is the variable storing the number to which the look-up will start
    starting_no = NumericProperty(3)
    suggestion_text = ''

    def __init__(self, **kwargs):
        super(MyTextInput, self).__init__(**kwargs)

        self.dropdown = CustomDropDown(force_below=True)
        notes = ['Features', 'Suggestions', 'Abreviations', 'Miscellaneous']
        for note in notes:
            # when adding widgets, we need to specify the height manually (disabling
            # the size_hint_y) so the dropdown can calculate the area it needs.
            btn = Button(text='%r' % note, size_hint_y=None, height=30)

            # for each button, attach a callback that will call the select() method
            # on the dropdown. We'll pass the text of the button as the data of the
            # selection.
            btn.bind(on_release=lambda btn: self.dropdown.select(btn.text))

            # then add the button inside the dropdown
            self.dropdown.add_widget(btn)

        # one last thing, listen for the selection in the dropdown list and
        # assign the data to the button text.
        self.dropdown.bind(on_select=lambda instance, x: setattr(self, 'text', x))

    def on_text(self, instance, value):
        # only open DropDown if it is not already open and this TextInput is displayed
        if self.dropdown.parent is None and self.get_parent_window() is not None:
            self.dropdown.open(self)

    def keyboard_on_key_down(self, window, keycode, text, modifiers):
        if self.suggestion_text and keycode[1] == 'tab':
            self.insert_text(self.suggestion_text + ' ')
            return True
        return super(MyTextInput, self).keyboard_on_key_down(window, keycode, text, modifiers)

还需要注释掉operator.kv中的RV:

                MyLayout:
                    orientation: 'vertical'
                    spacing: 2
                    code_inp: code_inp
                    MyTextInput:
                        id: code_inp
                        size_hint_x:1
                        multiline:False
                        size_hint_y:1
                        on_text_validate:root.update_purchases()
#                    RV:
#                        id:rv
#                        size_hint_x:1

这基本上只是一个概念证明。显然,需要更多的逻辑。

【讨论】:

  • 非常感谢您的帮助,我是 kivy 的新手,对我帮助很大
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-19
  • 2012-11-14
  • 2014-09-30
  • 2022-12-31
  • 2015-10-19
  • 2012-03-14
  • 1970-01-01
相关资源
最近更新 更多