Kivy:如何在 TextInput 中从右侧开始文本?

Kivy : How to start text from right side in TextInput?

当我输入 MyFloatInput TextInput 时,文本从 TextInput 的 right 一侧开始,它工作完美
但是我从 .py 设置了 MyFloatInput TextInput 的值然后它从左边开始 side.It 不显示在右边。
有人可以告诉我代码有什么问题吗?

test.py

import kivy

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

Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (400, 100)


class MyFloatInput(TextInput):

    def __init__(self, **kwargs):
        super(MyFloatInput, self).__init__(**kwargs)
        self.multiline = False

    def right_adjust(self, text):
        max_width = self.width - self.padding[0] - self.padding[2]
        new_text = text
        text_width = self._get_text_width(new_text, self.tab_width, self._label_cached)
        while text_width < max_width:
            new_text = ' ' + new_text
            text_width = self._get_text_width(new_text, self.tab_width, self._label_cached)
        while text_width >= max_width:
            if new_text[0] != ' ':
                break
            else:
                new_text = new_text[1:]
                text_width = self._get_text_width(new_text, self.tab_width, self._label_cached)
        return new_text

    def delete_selection(self, from_undo=False):
        if not self._selection:
            return
        cr = self.cursor[1]
        initial_len = len(self._lines[cr])
        a, b = self._selection_from, self._selection_to
        if a > b:
            a, b = b, a
        super(MyFloatInput, self).delete_selection(from_undo=from_undo)
        cur_text = self._lines[cr]
        super(MyFloatInput, self)._refresh_text(self.right_adjust(cur_text))
        final_len = len(self._lines[cr])
        self.cursor = self.get_cursor_from_index(final_len - (initial_len - b))

    def do_backspace(self, from_undo=False, mode='bkspc'):
        cc, cr = self.cursor
        initial_len = len(self._lines[cr])
        super(MyFloatInput, self).do_backspace(from_undo=from_undo, mode=mode)
        cc, cr = self.cursor
        cur_text = self._lines[cr]
        super(MyFloatInput, self)._refresh_text(self.right_adjust(cur_text))
        final_len = len(self._lines[cr])
        self.cursor = self.get_cursor_from_index(final_len - (initial_len-cc) + 1)

    def insert_text(self, the_text, from_undo=False):
        cc, cr = self.cursor
        cur_text = self._lines[cr]
        initial_len = len(cur_text)
        new_text = self.right_adjust(cur_text[:cc] + the_text + cur_text[cc:])
        try:
            num = float(new_text) # throw exception if new_text is invalid float
        except ValueError:
            return
        self._lines[cr] = ''
        super(MyFloatInput, self).insert_text(new_text, from_undo=from_undo)
        final_len = len(self._lines[cr])
        self.cursor = self.get_cursor_from_index(final_len - (initial_len-cc))

    def set_right_adj_text(self, text):
        num = float(text)  # throws exception if text is invalid float
        self._refresh_text(self.right_adjust(text))

    def on_text(self, instance, text):
        #num = float(text)  # throws exception if text is invalid float
        self._refresh_text(self.right_adjust(text))

class Testing(Screen):

    def __init__(self, **kwargs):
        super(Testing, self).__init__(**kwargs)
        Clock.schedule_once(lambda dt: setattr(self.test, 'text', str(100)))

class Test(App):

    def build(self):
        self.root = Builder.load_file('test.kv')
        return self.root


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

test.kv

Testing:
    test:test
    BoxLayout:
        orientation: "vertical"
        padding : 20, 20

        BoxLayout:
            orientation: "horizontal"
            padding: 10, 10
            spacing: 10, 10
            size_hint_x: .6

            Label:
                text: "No."
                text_size: self.size
                valign: 'middle'
                size_hint_x: .2

            MyFloatInput:
                size_hint_x: .6
                id : test

我不知道有什么方法可以使用 TextInput 可用的选项。但是可以通过扩展TextInput来完成。这是一个 MyFloatInput class:

import string

class MyFloatInput(TextInput):

    def __init__(self, **kwargs):
        super(MyFloatInput, self).__init__(**kwargs)
        self.multiline = False

    def insert_text(self, theText, from_undo=False):
        if theText not in string.digits and theText != '.':
            return
        if '.' in self.text and theText == '.':
            return

        maxWidth = self.width - self.padding[0] - self.padding[2]
        cc, cr = self.cursor
        curText = self._lines[cr]
        new_text = curText[:cc] + theText + curText[cc:]
        textWidth = self._get_text_width(new_text, self.tab_width, self._label_cached)
        while textWidth < maxWidth:
            new_text = ' ' + new_text
            textWidth = self._get_text_width(new_text, self.tab_width, self._label_cached)
        while textWidth >= maxWidth:
            if new_text[0] != ' ':
                break
            else:
                new_text = new_text[1:]
                textWidth = self._get_text_width(new_text, self.tab_width, self._label_cached)
        self._lines[cr] = ''
        self.cursor = (0,cr)
        super(MyFloatInput, self).insert_text(new_text, from_undo=from_undo)

这应该会做你想做的事并且也会做 float 过滤。要使用它,请将其包含在您的 .py 文件中并将 .kv 文件的 TextInput 部分替换为:

        MyFloatInput:
            size_hint_x: .2

请注意,这仅适用于单行输入,因此 __init__ 方法将 multiline 设置为 False。此代码使用以 _ 开头的方法和变量,因此如果更新 TextInput class,代码可能会中断。

我对 MyFloatInput class 进行了重大更改。它现在不再需要 string 导入。它现在处理删除选择,您现在可以使用 set_right_adj_text("some text") 方法从 .py 文件设置文本。这是改进后的 class:

class MyFloatInput(TextInput):

    def __init__(self, **kwargs):
        super(MyFloatInput, self).__init__(**kwargs)
        self.multiline = False

    def right_adjust(self, text):
        max_width = self.width - self.padding[0] - self.padding[2]
        new_text = text
        text_width = self._get_text_width(new_text, self.tab_width, self._label_cached)
        while text_width < max_width:
            new_text = ' ' + new_text
            text_width = self._get_text_width(new_text, self.tab_width, self._label_cached)
        while text_width >= max_width:
            if new_text[0] != ' ':
                break
            else:
                new_text = new_text[1:]
                text_width = self._get_text_width(new_text, self.tab_width, self._label_cached)
        return new_text

    def on_size(self, instance, value):
        super(MyFloatInput, self).on_size(instance, value)
        if len(self._lines) == 0:
            return True
        cc, cr = self.cursor
        cur_text = self._lines[cr]
        initial_len = len(cur_text)
        super(MyFloatInput, self)._refresh_text(self.right_adjust(cur_text))
        final_len = len(self._lines[cr])
        self.cursor = self.get_cursor_from_index(final_len - (initial_len - cc))
        return True

    def delete_selection(self, from_undo=False):
        if not self._selection:
            return
        cr = self.cursor[1]
        initial_len = len(self._lines[cr])
        a, b = self._selection_from, self._selection_to
        if a > b:
            a, b = b, a
        super(MyFloatInput, self).delete_selection(from_undo=from_undo)
        cur_text = self._lines[cr]
        super(MyFloatInput, self)._refresh_text(self.right_adjust(cur_text))
        final_len = len(self._lines[cr])
        self.cursor = self.get_cursor_from_index(final_len - (initial_len - b))

    def do_backspace(self, from_undo=False, mode='bkspc'):
        cc, cr = self.cursor
        initial_len = len(self._lines[cr])
        super(MyFloatInput, self).do_backspace(from_undo=from_undo, mode=mode)
        cc, cr = self.cursor
        cur_text = self._lines[cr]
        super(MyFloatInput, self)._refresh_text(self.right_adjust(cur_text))
        final_len = len(self._lines[cr])
        self.cursor = self.get_cursor_from_index(final_len - (initial_len-cc) + 1)

    def insert_text(self, the_text, from_undo=False):
        cc, cr = self.cursor
        cur_text = self._lines[cr]
        initial_len = len(cur_text)
        new_text = self.right_adjust(cur_text[:cc] + the_text + cur_text[cc:])
        try:
            num = float(new_text) # throw exception if new_text is invalid float
        except ValueError:
            return
        self._lines[cr] = ''
        super(MyFloatInput, self).insert_text(new_text, from_undo=from_undo)
        final_len = len(self._lines[cr])
        self.cursor = self.get_cursor_from_index(final_len - (initial_len-cc))

    def set_right_adj_text(self, text):
        num = float(text)  # throws exception if text is invalid float
        self._refresh_text(self.right_adjust(text))