This discussion is archived
2 Replies Latest reply: Nov 20, 2012 11:58 PM by 975244 RSS

TextField setting the caret to the end when loosing focus

975244 Newbie
Currently Being Moderated
Hey everyone,

I would like to set the caret of a TextField to the end of the text when the TextField loses the focus, so that the last part of the file name will be shwon and not the first part. I´ve tried the following:
ChangeListener<Boolean> onLooseFocus = new ChangeListener<Boolean>() 
         { 
              @Override
              public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) 
              {
                   if (!newValue.booleanValue()) 
                   {
                        textFieldDateiname.end();     
                                System.out.println(textFieldDateiname.getCaretPosition()); 
                                // At this point the caret is at the end and it will show:
                                //ReadOnlyIntegerProperty [bean: TextField[id=textFieldDateiname, styleClass=text-input text-field], name: caretPosition, value: 76]
                   }
              }
         };
this ChangeListener is added to the focusedProperty() method of my TextField
textFieldDateiname.focusedProperty().addListener(onLooseFocus);
It doesn´t work, although the caret is temporarily on the end of the text field.

Another question: If it works, I would like to reuse the ChangeListener onLooseFocus for diefferent TextField. So I would like to know which TextField lost the focus. I tried
observable.getSoruce(); // like it works with keyEvent
System.out.println(observable); // -> ReadOnlyBooleanProperty [bean: TextField[id=textFieldDateiname, styleClass=text-input text-field], name: focused, value: false]
So the id of the source of the ChangeEvent is known...

Any ideas?

Thanks,

Lukas

Edited by: 972241 on 20.11.2012 06:08
  • 1. Re: TextField setting the caret to the end when loosing focus
    James_D Guru
    Currently Being Moderated
    For the latter question, you can cast the Observable to a ReadOnlyProperty, and call getBean() on that; cast the results of the getBean() call to a TextField.

    I have no good solution to the main part of your question. It looks like the default behavior is to revert the carat position to the beginning of the text, and the listener that achieves that is executed after your custom listener.
    So the best hack I can see is to have a flag that overrides the carat position change. Set the flag to true on losing focus. Register a listener with the carat position property, and if the flag is set move the carat back to the end (then unset the flag).
    If you want to use the listeners on multiple text fields, instead of a flag, have a set of textfields which will have their carat positions changes overridden.

    This really is a hack; I'd like to think there's a better solution.
    import java.util.HashSet;
    import java.util.Set;
    
    import javafx.application.Application;
    import javafx.beans.property.ReadOnlyProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.TextField;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    
    public class TestFieldFocusTest extends Application {
    
      @Override
      public void start(Stage primaryStage) throws Exception {
        final VBox root = new VBox();
        final TextField tf1 = new TextField();
        final TextField tf2 = new TextField();
        
        final Set<TextField> overrideNextCaratChange = new HashSet<TextField>();
    
        final ChangeListener<Boolean> onLoseFocus = new ChangeListener<Boolean>() {
          @Override
          public void changed(ObservableValue<? extends Boolean> observable,
              Boolean oldValue, Boolean newValue) {
            ReadOnlyProperty<? extends Boolean> property = (ReadOnlyProperty<? extends Boolean>) observable ;
            TextField tf = (TextField) property.getBean() ;
            if (!newValue.booleanValue()) {
              tf.end();
              overrideNextCaratChange.add(tf);
            }
          }
        };
        
        final ChangeListener<Number> onCaratChange = new ChangeListener<Number>() {
          @Override
          public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
            ReadOnlyProperty<? extends Number> property = (ReadOnlyProperty<? extends Number>) observable ;
            TextField tf = (TextField) property.getBean() ;
            if (overrideNextCaratChange.contains(tf)) {
              tf.end();
              overrideNextCaratChange.remove(tf);
            }
          }
        };
        
        tf1.focusedProperty().addListener(onLoseFocus);
        tf1.caretPositionProperty().addListener(onCaratChange);
        tf2.focusedProperty().addListener(onLoseFocus);
        tf2.caretPositionProperty().addListener(onCaratChange);
        
        Button info = new Button("Show info");
        info.setOnAction(new EventHandler<ActionEvent>() {
          
          @Override
          public void handle(ActionEvent arg0) {
            System.out.printf("Selection: %s (%d characters). Carat position: %d%n",
                tf1.getSelection(),
                tf1.getSelectedText().length(),
                tf1.getCaretPosition());
          }
        });
        
        root.getChildren().addAll(tf1, tf2, info);
        Scene scene = new Scene(root, 100, 200);
        primaryStage.setScene(scene);
        primaryStage.show();
      }
    
      public static void main(String[] args) {
        launch(args);
      }
    
    }
  • 2. Re: TextField setting the caret to the end when loosing focus
    975244 Newbie
    Currently Being Moderated
    Hi James,

    thanks a lot! The cast for observable works perfectly!

    The second part works as well, although it is kind of intricate. There should be a way to override the default operation, which sets the caret to the start of the text field...nevertheless, great work!

    Greetz,

    Lukas

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points