Kivy TextInput IndexError: list index out of range

使用场景

在一个触摸屏POS中使用一个Kivy 的TextInput控件做商品扫码输入, 要求把输入框隐藏了

环境

Python: 3.6.2
Kivy: 1.11.1
OS:Windows10

代码

<FunButtonScreen>:
    BoxLayout:
        size_hint:1,1
        orientation:'vertical'
        TextInput:
            id: id_scan_plu
            size_hint: None, None
            height: 0
            width: 0
            cursor_width: 0
            # multiline: False
        FunButtonBox:
            size_hint: 1, 1
            id: button_box

以上代码通过heightwidthid为id_scan_plu的TextInput控件隐藏了, 效果图如下红框处实际上有一个TextInput输入框

效果图

问题

POS是使用的触摸屏大部分是正常的,偶尔已报IndexError: list index out of range异常, 而KeyEvent只有扫码枪, 为什么会报key_down异常呢?

2020-02-17 19:14:09,114 MainThread INFO : Base: Leaving application in progress...
2020-02-17 19:14:09,115 MainThread WARNING : stderr: Traceback (most recent call last):
2020-02-17 19:14:09,115 MainThread WARNING : stderr:   File "pos_main.py", line 90, in <module>
2020-02-17 19:14:09,116 MainThread WARNING : stderr:     main()
2020-02-17 19:14:09,117 MainThread WARNING : stderr:   File "pos_main.py", line 77, in main
2020-02-17 19:14:09,117 MainThread WARNING : stderr:     MainWindow().run()
2020-02-17 19:14:09,118 MainThread WARNING : stderr:   File "d:\Python35\lib\site-packages\kivy\app.py", line 828, in run
2020-02-17 19:14:09,121 MainThread WARNING : stderr:     runTouchApp()
2020-02-17 19:14:09,122 MainThread WARNING : stderr:   File "d:\Python35\lib\site-packages\kivy\base.py", line 504, in runTouchApp
2020-02-17 19:14:09,124 MainThread WARNING : stderr:     EventLoop.window.mainloop()
2020-02-17 19:14:09,124 MainThread WARNING : stderr:   File "d:\Python35\lib\site-packages\kivy\core\window\window_sdl2.py", line 663, in mainloop
2020-02-17 19:14:09,126 MainThread WARNING : stderr:     self._mainloop()
2020-02-17 19:14:09,127 MainThread WARNING : stderr:   File "d:\Python35\lib\site-packages\kivy\core\window\window_sdl2.py", line 602, in _mainloop
2020-02-17 19:14:09,128 MainThread WARNING : stderr:     self.modifiers):
2020-02-17 19:14:09,129 MainThread WARNING : stderr:   File "kivy\_event.pyx", line 714, in kivy._event.EventDispatcher.dispatch (kivy\_event.c:8146)
2020-02-17 19:14:09,130 MainThread WARNING : stderr:   File "kivy\_event.pyx", line 1225, in kivy._event.EventObservers.dispatch (kivy\_event.c:14035)
2020-02-17 19:14:09,132 MainThread WARNING : stderr:   File "kivy\_event.pyx", line 1149, in kivy._event.EventObservers._dispatch (kivy\_event.c:13564)
2020-02-17 19:14:09,133 MainThread WARNING : stderr:   File "d:\Python35\lib\site-packages\kivy\core\window\__init__.py", line 159, in _on_window_key_down
2020-02-17 19:14:09,135 MainThread WARNING : stderr:     return self.dispatch('on_key_down', keycode, text, modifiers)
2020-02-17 19:14:09,136 MainThread WARNING : stderr:   File "kivy\_event.pyx", line 714, in kivy._event.EventDispatcher.dispatch (kivy\_event.c:8146)
2020-02-17 19:14:09,137 MainThread WARNING : stderr:   File "kivy\_event.pyx", line 1225, in kivy._event.EventObservers.dispatch (kivy\_event.c:14035)
2020-02-17 19:14:09,139 MainThread WARNING : stderr:   File "kivy\_event.pyx", line 1149, in kivy._event.EventObservers._dispatch (kivy\_event.c:13564)
2020-02-17 19:14:09,140 MainThread WARNING : stderr:   File "d:\Python35\lib\site-packages\kivy\uix\textinput.py", line 2438, in keyboard_on_key_down
2020-02-17 19:14:09,145 MainThread WARNING : stderr:     self._key_down(key)
2020-02-17 19:14:09,145 MainThread WARNING : stderr:   File "d:\Python35\lib\site-packages\kivy\uix\textinput.py", line 2279, in _key_down
2020-02-17 19:14:09,149 MainThread WARNING : stderr:     self._alt_l or self._alt_r)
2020-02-17 19:14:09,149 MainThread WARNING : stderr:   File "d:\Python35\lib\site-packages\kivy\uix\textinput.py", line 1162, in do_cursor_movement
2020-02-17 19:14:09,151 MainThread WARNING : stderr:     col = min(len(self._lines[row]), col)
2020-02-17 19:14:09,152 MainThread WARNING : stderr: IndexError: list index out of range

这个问题在百度、bing、github、SO都没有搜到解决办法,只好阅读源码Python35\lib\site-packages\kivy\uix\textinput.py

def do_cursor_movement(self, action, control=False, alt=False):
        '''Move the cursor relative to its current position.
        Action can be one of :

            - cursor_left: move the cursor to the left
            - cursor_right: move the cursor to the right
            - cursor_up: move the cursor on the previous line
            - cursor_down: move the cursor on the next line
            - cursor_home: move the cursor at the start of the current line
            - cursor_end: move the cursor at the end of current line
            - cursor_pgup: move one "page" before
            - cursor_pgdown: move one "page" after

        In addition, the behavior of certain actions can be modified:

            - control + cursor_left: move the cursor one word to the left
            - control + cursor_right: move the cursor one word to the right
            - control + cursor_up: scroll up one line
            - control + cursor_down: scroll down one line
            - control + cursor_home: go to beginning of text
            - control + cursor_end: go to end of text
            - alt + cursor_up: shift line(s) up
            - alt + cursor_down: shift line(s) down

        .. versionchanged:: 1.9.1

        '''
        if not self._lines:
            return
        pgmove_speed = int(self.height /
            (self.line_height + self.line_spacing) - 1)
        col, row = self.cursor
        if action == 'cursor_up':
            if self.multiline and control:
                self.scroll_y = max(0, self.scroll_y - self.line_height)
            elif not self.readonly and self.multiline and alt:
                self._shift_lines(-1)
                return
            else:
                row = max(row - 1, 0)
                col = min(len(self._lines[row]), col)
        elif action == 'cursor_down':
            if self.multiline and control:
                maxy = self.minimum_height - self.height
                self.scroll_y = max(0, min(maxy,
                                           self.scroll_y + self.line_height))
            elif not self.readonly and self.multiline and alt:
                self._shift_lines(1)
                return
            else:
                row = min(row + 1, len(self._lines) - 1)
                col = min(len(self._lines[row]), col)
        elif action == 'cursor_home':
            col = 0
            if control:
                row = 0
        elif action == 'cursor_end':
            if control:
                row = len(self._lines) - 1
            col = len(self._lines[row])
        elif action == 'cursor_pgup':
            row = max(0, row - pgmove_speed)
            col = min(len(self._lines[row]), col)
        elif action == 'cursor_pgdown':
            row = min(row + pgmove_speed, len(self._lines) - 1)
            col = min(len(self._lines[row]), col)
        elif (self._selection and self._selection_finished and
                self._selection_from < self._selection_to and
                action == 'cursor_left'):
            current_selection_to = self._selection_to
            while self._selection_from != current_selection_to:
                current_selection_to -= 1
                if col:
                    col -= 1
                else:
                    row -= 1
                    col = len(self._lines[row])
        elif (self._selection and self._selection_finished and
                self._selection_from > self._selection_to and
                action == 'cursor_right'):
            current_selection_to = self._selection_to
            while self._selection_from != current_selection_to:
                current_selection_to += 1
                if len(self._lines[row]) > col:
                    col += 1
                else:
                    row += 1
                    col = 0

        elif action == 'cursor_left':
            if not self.password and control:
                col, row = self._move_cursor_word_left()
            else:
                if col == 0:
                    if row:
                        row -= 1
                        col = len(self._lines[row])
                else:
                    col, row = col - 1, row
        elif action == 'cursor_right':
            if not self.password and control:
                col, row = self._move_cursor_word_right()
            else:
                if col == len(self._lines[row]):
                    if row < len(self._lines) - 1:
                        col = 0
                        row += 1
                else:
                    col, row = col + 1, row

        dont_move_cursor = control and action in ['cursor_up', 'cursor_down']
        if dont_move_cursor:
            self._trigger_update_graphics()
        else:
            self.cursor = (col, row)

原来店里配置了外置键盘,当输入Pgup、PgDn键是会引发异常, 由于通过height和width 都是0所以没法上下滚动而异常

解决办法

通过透明属性隐藏控件, 即把颜色的rgba都是设置成0, 背景设置为空

<FunButtonScreen>:
    BoxLayout:
        size_hint:1,1
        orientation:'vertical'
        TextInput:
            id: id_scan_plu
            size_hint: None, None
            height: 40
            width: 120
            cursor_width: 0
            multiline: False
            color: 0, 0, 0, 0
            background_normal: ""
            background_active: ""
            cursor_color: 0, 0, 0, 0
            background_color: 0, 0, 0, 0
            foreground_color: 0, 0, 0, 0
            
        FunButtonBox:
            size_hint: 1, 1
            id: button_box
posted @ 2020-02-18 10:15  Onsunsl  阅读(460)  评论(0编辑  收藏  举报