I am using Python 2.7 and kivy.
When i click outside of Text
into TextInput
then i cannot type.
Can someone help me that when I click into textInput
then how to set or shift cursor
end of text?
i am using instance.cursor = (len(instance.text), 0)
in def on_focus()
for set position of cursor but its not working.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.uix.textinput import TextInput
from kivy.properties import BooleanProperty, ListProperty, ObjectProperty, NumericProperty, DictProperty, StringProperty
Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (400, 50)
class RightFloatInput(TextInput):
decimal = NumericProperty(0)
negative = False
def __init__(self, **kwargs):
super(RightFloatInput, self).__init__(**kwargs)
self.multiline = False
def right_adjust(self, text):
max_width = self.width - self.padding[0] - self.padding[2]
new_text = text.strip()
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 != ' ':
break
else:
new_text = new_text[1:]
text_width = self._get_text_width(new_text, self.tab_width, self._label_cached)
return new_text.rstrip()
def on_size(self, instance, value):
super(RightFloatInput, 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(RightFloatInput, 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
def delete_selection(self, from_undo=False):
# print('delete_selection')
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(RightFloatInput, self).delete_selection(from_undo=from_undo)
cur_text = self._lines[cr]
super(RightFloatInput, 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'):
# print('do_backspace')
cc, cr = self.cursor
initial_len = len(self._lines[cr])
super(RightFloatInput, self).do_backspace(from_undo=from_undo, mode=mode)
cc, cr = self.cursor
cur_text = self._lines[cr]
super(RightFloatInput, 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):
if self.readonly == True:
return
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:
if self.negative == True:
if str(the_text) != "-":
num = float(new_text) # throw exception if new_text is invalid float
else:
num = float(new_text)
except ValueError:
return
if str(the_text) != "-":
if num > 10000000:
return
self._lines[cr] = ''
self._refresh_text(self.right_adjust(new_text))
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):
self._refresh_text(self.right_adjust(text))
def on_focus(self, instance, isFocused):
if isFocused:
final_len = len(instance.text)
instance.cursor = self.get_cursor_from_index(final_len)
Clock.schedule_once(lambda dt: self.selected_text())
if instance.focus:
self.cursor = (final_len, 0)
print("TextInput is focused [focus={}]".format(instance.focus))
instance.cursor = (len(instance.text), 0)
Clock.schedule_once(lambda dt: instance.select_all())
return
else:
try:
num = float(self.text.strip()) # throw exception if new_text is invalid float
except ValueError:
return
new_text = self.text.strip()
new_text = self.right_adjust(new_text)
self._refresh_text(new_text)
final_len = len(new_text)
self.cursor = self.get_cursor_from_index(final_len)
def on_touch_down_2(self, instanse):
final_len = len(self.text)
self.cursor = self.get_cursor_from_index(final_len)
return False
def selected_text(self):
ci = self.cursor_index()
cc = self.cursor_col
line = self._lines[self.cursor_row]
len_line = len(line)
start = max(0, len(line[:cc]) - line[:cc].rfind(u' ') - 1)
end = line[cc:].find(u' ')
end = end if end > - 1 else (len_line - cc)
Clock.schedule_once(lambda dt: self.select_text(ci - start, ci + end))
def on_text(self, instance, text):
if text.count('-') > 1:
self.text = "-"
return
new_text = self.right_adjust(text)
self._refresh_text(new_text)
final_len = len(new_text)
self.cursor = self.get_cursor_from_index(final_len)
def on_text_validate_old(self):
try:
num = float(self.text.strip()) # throw exception if new_text is invalid float
except ValueError:
return
if self.decimal == 1 and self.text.strip() != "":
self.text = str("{0:.1f}".format(float(self.text.strip())))
if self.decimal == 2 and self.text.strip() != "":
self.text = str("{0:.2f}".format(float(self.text.strip())))
if self.decimal == 3 and self.text.strip() != "":
self.text = str("{0:.3f}".format(float(self.text.strip())))
new_text = self.right_adjust(self.text)
self._refresh_text(new_text)
final_len = len(new_text)
self.cursor = self.get_cursor_from_index(final_len)
class abc(BoxLayout):
pass
class Test(App):
def build(self):
return abc()
if __name__ == '__main__':
Test().run()
<abc>:
BoxLayout:
orientation: "vertical"
size_hint_y: .5
BoxLayout:
orientation: "horizontal"
spacing: 10, 10
size_hint_x: .6
Label:
text: "TEXT"
text_size: self.size
valign: 'middle'
size_hint_x: .2
RightFloatInput:
size_hint_x: .4
text : "100"
Add the following:
from functools import partial
set_cursor()
from functools import partial
...
def set_cursor(self, instance, dt):
instance.cursor = (len(instance.text), 0)
def on_focus(self, instance, isFocused):
if instance.focus:
final_len = len(instance.text)
self.cursor = (final_len, 0)
print("TextInput is focused [focus={}]".format(instance.focus))
Clock.schedule_once(lambda dt: instance.select_all())
Clock.schedule_once(partial(self.set_cursor, instance), 1)
return
else:
try:
num = float(self.text.strip()) # throw exception if new_text is invalid float
except ValueError:
return
new_text = self.text.strip()
new_text = self.right_adjust(new_text)
self._refresh_text(new_text)
final_len = len(new_text)
self.cursor = self.get_cursor_from_index(final_len)
To set cursor at end of text, use instance.cursor = (len(instance.text), 0)
def on_focus(self, instance):
if instance.focus:
print("TextInput is focused [focus={}]".format(instance.focus))
instance.cursor = (len(instance.text), 0)
Clock.schedule_once(lambda dt: instance.select_all())
else:
print("TextInput is defocused [focus={}]".format(instance.focus))
There is a typo in the Kivy documentation. The cursor is tuple of (col, row) and not (row, col)
cursor
Tuple of (row, col) values indicating the current cursor position. You can set a new (row, col) if you want to move the cursor. The scrolling area will be automatically updated to ensure that the cursor is visible inside the viewport.
cursor is an AliasProperty.