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

时间:2018-03-14 12:22:26

标签: python python-2.7 kivy kivy-language

当我输入MyFloatInput TextInput时,文字从TextInput的right侧开始,它的工作正常 但我从MyFloatInput设置了.py TextInput的值,然后从左侧开始。它没有显示在右侧。
有人能告诉我代码有什么问题吗?

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

2 个答案:

答案 0 :(得分:4)

我不知道如何使用TextInput的可用选项来做到这一点。但可以通过扩展TextInput来完成。这是一个MyFloatInput类:

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类更新,代码可能会中断。

答案 1 :(得分:2)

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

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))