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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章