How to initialize cursor position for Input widget? #1680
-
I want to initialize an Input widget with some text and set a particular cursor position. Here's what I tried (Textual version 0.10.0): from textual.app import App
from textual.binding import Binding
from textual.widgets import Input, Footer
class Test(App):
BINDINGS = [Binding('ctrl+u', 'cursor', 'Cursor', show=True)]
def __init__(self):
super().__init__()
self.ip = Input(value="apple")
def compose(self):
yield self.ip
yield Footer()
def on_mount(self):
self.ip.focus()
self.ip.cursor_position = 3
def action_cursor(self):
self.ip.cursor_position = 3
if __name__ == '__main__':
app = Test()
app.run() When I run the above code, the cursor position is always at the end. When I press |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
The issue here is that Unfortunately it seems that, right at the moment, there's no easy way to override that behaviour -- the obvious thing of making a custom input widget from from textual.app import App
from textual.binding import Binding
from textual.widgets import Input, Footer
class InputAt(Input):
def __init__(self, position, *args, **kwargs):
super().__init__(*args, **kwargs)
self._on_focus_position = position
def _on_focus_cursor_position(self):
self.cursor_position = self._on_focus_position
def on_focus(self):
self.call_after_refresh(self._on_focus_cursor_position)
class Test(App):
BINDINGS = [Binding('ctrl+u', 'cursor', 'Cursor', show=True)]
def __init__(self):
super().__init__()
self.ip = InputAt(3, value="apple")
def compose(self):
yield self.ip
yield Footer()
def on_mount(self):
self.ip.focus()
def action_cursor(self):
self.ip.cursor_position = 3
if __name__ == '__main__':
app = Test()
app.run() Simply put, it sets things up so that once focus has been set, it sets up some code to be run once all other refresh work has taken place to finally settle the cursor position at the given location. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the explanation and the workaround! Will be great if something like this is added to the |
Beta Was this translation helpful? Give feedback.
The issue here is that
Input
has anon_focus
handler which always sets the cursor position to the end of the input (funnily enough I was wondering about the design choice there just this morning). While you are setting the cursor position after callingfocus
, I would imagine that due to the async nature of Textual theon_focus
of theInput
is happening after youron_mount
has finished (see the code forWidget.focus
if you want to dive deeper).Unfortunately it seems that, right at the moment, there's no easy way to override that behaviour -- the obvious thing of making a custom input widget from
Input
and just overridingon_focus
doesn't quite work out. It's a little bit hacky, but here's…