Kivy. Problem z TextInput i tabulatorami w linii

0

Witam ponownie.
Jak odczytać wyraz pod kursorem w TextInput z Kivy jeśli kolumna kursora nie uwzględnia tabulacji które występują po lewej stronie w linii.
Ma ktoś jakiś pomysł?
Czy to nie jakiś bug?

Minimalny przykład:

# Dwa tabulatory
#         v  v
lorem="""		quis nostrum e
nisi ut aliqui
"""
def f_write(*Data):
	print(txt.cursor)
	txt.focus=True
	return None
def on_start(*Data):
	txt.cursor=(1,3)
	txt.focus=True	
	return None

lay=BoxLayout(size_hint=(1,1),orientation='vertical')
txt=TextInput(text=lorem,size_hint=(1,.9),multiline=True,font_name='DejaVuSansMono.ttf',)
txt.tab_width=4
btn=Button(text="Push",size_hint=(1,.1))
btn.bind(on_release=f_write)
lay.add_widget(btn)
lay.add_widget(txt)
Clock.schedule_once(lambda _: on_start())
runTouchApp(lay)

U mnie wygląda to tak. Font Mono

screenshot-20211029200747.png

Pozdrawiam
Radosław Głebicki

2

Logika wydaje się poprawna, tyle że txt.cursor[1] daje ci pozycję liczoną w znakach, to że tabulacja ma szerokość tab_width możesz uwzględnić samemu

def f_write(*Data):
    col, row =  txt.cursor
    line = txt._lines[row][0:col]
    print(len(line.replace('\t', ' ' * txt.tab_width)))
    txt.focus=True
    return None

Jest też txt.cursor_offset(), które daje ci offset w pixelach.

0

@Spearhead: Dodatkowe pytanko. Czy można wyedytować linię przez TextInput._lines[index] i jakoś odświeżyć zawartość TextInput?

Można, ale manipulowanie wewnętrzną zmienną (podkreślenie z przodu) jest złym pomysłem jeśli nie wiesz dobrze co robisz.

Tak patrząc jeszcze raz na twój problem to myślę, że mniej problemów będziesz miał jeśli po prostu zabronisz używania tabulatorów w tekście, co można osiągnąć przez stworzenie podklasy TextInput:

class NoTabTextInput(TextInput):
    def insert_text(self, substring, from_undo=False):
        s = substring.replace('\t', ' ' * self.tab_width)
        return super().insert_text(s, from_undo=from_undo)

Jak użyjesz NoTabTextInput w miejsce TextInput, to wpisując/wklejając tabulacje zostaną one od razu zastąpione przez kilka spacji i twoje problemy powinny zniknąć. Uwaga: jeśli zmodyfikujesz atrybut text bezpośrednio to ta metoda nie będzie wywoływana, więc też trzeba będzie zrobić replace.

1 użytkowników online, w tym zalogowanych: 0, gości: 1