单击“TextInput”对象后在 Kivy 中重新捕获键盘焦点

Recapture keyboard focus in Kivy after clicking out of a `TextInput` object

以下代码创建了一个 Kivy 应用,只有一个屏幕 MainScreen,显示 LabelTextInput 对象。

如果您在应用首次加载时进行一些键盘输入,它会在控制台中打印出有关按下哪个键的信息。但是,如果您随后单击 TextInput 对象,键盘会重新聚焦,以便您可以键入 TextInput 对象。但是,一旦您单击退出 TextInput 对象,例如在标签或背景上,按更多键,不执行相同的控制台打印操作;键盘似乎不是来自 TextInput 对象的 'defocus'。

单击 TextInput 对象后如何重新获得键盘焦点?

from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.textinput import TextInput

kv = '''ScreenManagement:
    MainScreen:

<MainScreen>:
    name: "main"
    BoxLayout:
        Label:
            text: "Label"
            font_size: 20
            size_hint: 0.2,0.1
        TextInput
            input_filter: 'float'
            font_size: 20
            hint_text: "Input Text"
            size_hint: 0.2,0.1'''

class MainScreen(Screen):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_keyboard_down)

    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

    def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
        print('INFO: The key', keycode, 'has been pressed')

        return True # return True to accept the key. Otherwise, it will be used by the system.

class ScreenManagement(ScreenManager):
    pass

class MainApp(App):
    def build(self):
        return Builder.load_string(kv)

if __name__ == "__main__":
    MainApp().run()

一个可能的解决方案是使用 on_touch_down 事件并在您按下不包含 TextInput 的部分时重新配置键盘:

class MainScreen(Screen):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.config_keyboard()

    def on_touch_down(self, touch):
        self.isTextInput = False

        def filter(widget):
            for child in widget.children:
                filter(child)
            if isinstance(widget, TextInput) and widget.collide_point(*touch.pos):
                self.isTextInput = True
                widget.on_touch_down(touch)

        filter(self)

        if not self.isTextInput and self._keyboard is None:
            self.config_keyboard()

    def config_keyboard(self):
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_keyboard_down)

    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

    def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
        print('INFO: The key', keycode, 'has been pressed')

        return True # return True to accept the key. Otherwise, it will be used by the system.