Move text field cursor to end of text

I Have a Text Field component , that has a characters remaining label, and also limits the amount
of characters allowed. i have it working but the problem is that when the limit is reached(20 characters) the Cursor of the text box goes to the first character in the field

This is the Script that i found that works for the limit, but the cursor goes to the first character, I want the text cursor to stay in the last character.

if event.propertyName == 'text': 
    if len(event.newValue) > 20:
        def doLate(evt=event): 
	       evt.source.text = evt.oldValue
        system.util.invokeLater(doLate)

image

in this example i would type two more characterts it would at 1 more character and then the cursor moves to before the M. i need to stay at then end.

Turn off ‘Defer Update’ and use java.awt.Robot:

if event.propertyName == 'text': 
  if len(event.newValue) > 20:
    from java.awt import Robot
    from java.awt.event import KeyEvent
    robot = Robot()
    robot.keyPress(KeyEvent.VK_BACK_SPACE)
    robot.keyRelease(KeyEvent.VK_BACK_SPACE)

If you need the Defer Update functionality, you’ll need to add scripts to the keyPressed and focusLost events.

Here is a demo to illustrate. Text Box 1 is limited to 5 characters, and pressing Enter or shifting focus writes the contents to Text Box 2.

Limit Textbox_2019-03-02_0735.proj (6.1 KB)

2019-03-02_7-45-06

2 Likes

I like your original event, but I’d add calls to set the selection to the 20th character, and I’d keep the last character as the new 20th. Like so:

if event.propertyName == 'text': 
	if len(event.newValue) > 20:
		def doLate(evt=event): 
			evt.source.text = event.newValue[:19]+event.newValue[-1]
			evt.source.selectionEnd = 20
			evt.source.selectionStart = 19
	system.util.invokeLater(doLate)

See JTextComponent.setSelectionStart() for the details.

2 Likes

Fyi. i ended up using this.

if event.propertyName == 'text': 
	if len(event.newValue) > 20:
    	def doLate(evt=event): 
	    	evt.source.text = evt.oldValue
	        evt.source.selectionEnd = 20
	    	evt.source.selectionStart = 20
	    system.util.invokeLater(doLate)

the reason why i used the oldValue, is that this is for a password field, so let’s say if the user is typing and does not look that field, if he types 22 characters, with your solution the character twenty will be replaced and if they approved that password, then they will not know that it was actually changed automatically with the script, so next login they will have incorrect password. i thougth it would be better to keep the old value, that way if the password it’s type next login if they type the same first 20 characters, password will be correct.

2 Likes

I apologize for necroposting, but I think it's worth doing in this case. I would advise being extremely cautious about using an approach like this. If the user were to tab/click/navigate away from the text box during the time window in which those KeyEvents were being processed (which is longer than you might think), the JVM will simulate those key presses wherever the user's focus is at - leading to unexpected, potentially dangerous behavior.

Generally speaking, it is virtually never a good idea to use Java.Robot outside of UI unit testing. Using it to bandaid over a text selection issue in an HMI application? You're just asking for trouble.

1 Like