使用Kivy或KivyMD的TextInput小部件,我无法用键盘上的箭头(从数字键盘)移动光标



我正在Windows 10计算机上测试Kivy。当我点击TextInput小部件时,我可以使用键盘上的"倒T"箭头键入和移动光标,但不能使用我一直使用的数字键盘上的箭头(NumLock=Off(。有解决方案吗?

您可以使用一个扩展TextInput并使用数字填充箭头的类。这里有一个例子:

class MyTextInput(TextInput):
def keyboard_on_key_down(self, window, keycode, text, modifiers):
if 'numlock' not in modifiers:
if keycode[0] == 264: # up arrow
self.do_cursor_movement('cursor_up')
elif keycode[0] == 262:  # right arrow
self.do_cursor_movement('cursor_right')
elif keycode[0] == 258:  # down arrow
self.do_cursor_movement('cursor_down')
elif keycode[0] == 260:  # left arrow
self.do_cursor_movement('cursor_left')
return super(MyTextInput, self).keyboard_on_key_down(window, keycode, text, modifiers)

在John Anderson的帮助下,当numlock关闭时,我能够通过将numpad密钥重新映射为常规密钥来找到一个完整的解决方案:

from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivymd.app import MDApp
from kivymd.uix.textfield import MDTextField
numpad_map = dict(
numpad1=(279, 'end'     ),      #257
numpad2=(274, 'down'    ),      #258
numpad3=(281, 'pagedown'),      #259
numpad4=(276, 'left'    ),      #260
numpad6=(275, 'right'   ),      #262
numpad7=(278, 'home'    ),      #263
numpad8=(273, 'up'      ),      #264
numpad9=(280, 'pageup'  ),      #265
numpaddecimal=(127, 'delete'),  #266
)
def fix_numpad(keycode, modifiers):
"""This function actually remap numpad arrows to regular arrows if numlock is off"""
keynum, keylbl = keycode
if 'numlock' not in modifiers and keylbl in numpad_map:
keycode = numpad_map[keylbl]
return keycode
class TextInput2(TextInput):
def keyboard_on_key_down(self, window, keycode, text, modifiers):
keycode = fix_numpad(keycode, modifiers)
return super().keyboard_on_key_down(window, keycode, text, modifiers)
class MDTextField2(MDTextField):
def keyboard_on_key_down(self, window, keycode, text, modifiers):
keycode = fix_numpad(keycode, modifiers)
return super().keyboard_on_key_down(window, keycode, text, modifiers)
KV = """
MDBoxLayout:
orientation: 'vertical'
md_bg_color: app.theme_cls.bg_normal
TextInput2:
MDTextField2:
"""
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()

EDIT:在源代码中进一步挖掘,我意识到MDTextField有许多子类,并且继承自FixedHintTextInput,后者继承自TextInput所以我找到了一种通用的方法来修补TextInput我不确定这是最健壮的解决方案,但我觉得它有点优雅,因为它修复了所有小部件的行为,而不必更改布局中的类名(直到kivy源代码被实际修补(。这是代码:

from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivymd.app import MDApp
def wrap_class_function(class_type, fn_attr_name, fn_wrapper_maker):
"""Replaces a method at the Class-level (class function) so that it affects
all instance methods (current and future, including subclasses)"""
old_fn = getattr(class_type, fn_attr_name)    # Get original class function
new_fn = fn_wrapper_maker(old_fn)             # Create new wrapper around it
new_fn.__name__ = fn_attr_name                # Set the __name__ of wrapper (so bindings still work)
setattr(class_type, fn_attr_name, new_fn)     # Replace old function with new one
def keyboard_on_key_down_wrapper_maker(original_fn):
"""Creates a wrapper function that applies the numpad patch, to be used
directly on TextInput base class (to fix all subclasses)"""
numpad_map = dict(
numpad1=(279, 'end'     ),      #257
numpad2=(274, 'down'    ),      #258
numpad3=(281, 'pagedown'),      #259
numpad4=(276, 'left'    ),      #260
numpad6=(275, 'right'   ),      #262
numpad7=(278, 'home'    ),      #263
numpad8=(273, 'up'      ),      #264
numpad9=(280, 'pageup'  ),      #265
numpaddecimal=(127, 'delete'),  #266
)
def keyboard_on_key_down_wrapper(self, window, keycode, text, modifiers):
key, key_str = keycode
if 'numlock' not in modifiers and key_str in numpad_map:
keycode = numpad_map[key_str]
return original_fn(self, window, keycode, text, modifiers)
return keyboard_on_key_down_wrapper
wrap_class_function(TextInput, 'keyboard_on_key_down', keyboard_on_key_down_wrapper_maker)
KV = """
MDBoxLayout:
orientation: 'vertical'
md_bg_color: app.theme_cls.bg_normal
TextInput:
MDTextField:  # This widget inherits TextInput patch
"""
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()

相关内容

  • 没有找到相关文章