Reputation: 734
I'm using a TextField
to display the path of a directory the user has opened in my application.
Currently, if the path can't fit inside the TextField
, upon focusing away/clicking away from this control, it looks like as if the path has become truncated:
I want the behaviour of TextField
set such that when I focus away from it, the path shown inside automatically scrolls to the right and the user is able to see the directory they've opened. I.e. something like this:
How can I achieve this? I've tried adapting the answer given from here
as follows in initialize()
method in my FXML Controller
class:
// Controller class fields
@FXML TextField txtMoisParentDirectory;
private String moisParentDirectory;
// ...
txtMoisParentDirectory.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldStr, String newStr) {
moisParentDirectory = newStr;
txtMoisParentDirectory.selectPositionCaret(moisParentDirectory.length());
txtMoisParentDirectory.deselect();
}
});
However it doesn't work.
Upvotes: 1
Views: 2611
Reputation: 61
Since the other answers didn't work for me here is a solution that should do the trick:
private TextField txtField;
// Both ChangeListeners just call moveCaretToEnd(), we need them both because of differing data types we are listening to
private final ChangeListener<Number> caretChangeListener = (observable, oldValue, newValue) -> moveCaretToEnd();
private final ChangeListener<String> textChangeListener = (observable, oldValue, newValue) -> moveCaretToEnd();
// This method moves the caret to the end of the text
private void moveCaretToEnd() {
Platform.runLater(() -> {
txtField.deselect();
txtField.end();
});
}
public void initialize() {
// Immediatly add the listeners on initialization (or once you created the TextField if you are not using FXML)
txtField.caretPositionProperty().addListener(caretChangeListener);
txtField.textProperty().addListener(textChangeListener);
txtField.focusedProperty().addListener((observable, oldValue, isFocused) -> {
if (isFocused) {
// once the TextField has been focused remove the listeners to enable normal editing of the text
txtField.caretPositionProperty().removeListener(caretChangeListener);
txtField.textProperty().removeListener(textChangeListener);
} else {
// when the focus is lost apply the listeners again
moveCaretToEnd();
txtField.caretPositionProperty().addListener(caretChangeListener);
txtField.textProperty().addListener(textChangeListener);
}
});
}
Upvotes: 1
Reputation: 11
tf.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
int location = tf.getText().length();
Platform.runLater(() -> {
tf.positionCaret(location);
});
}
});
this is also work
Upvotes: 1
Reputation: 1776
Your problem is based on two events, the length of the text entered and the loss of focus, so to solve it I used the properties textProperty()
and focusedProperty()
and here is the result :
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Launcher extends Application{
private Pane root = new Pane();
private Scene scene;
private TextField tf = new TextField();
private TextField tft = new TextField();
private int location = 0;
@Override
public void start(Stage stage) throws Exception {
scrollChange();
tft.setLayoutX(300);
root.getChildren().addAll(tft,tf);
scene = new Scene(root,400,400);
stage.setScene(scene);
stage.show();
}
private void scrollChange(){
tf.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
location = tf.getText().length();
}
});
tf.focusedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if(!newValue){
Platform.runLater( new Runnable() {
@Override
public void run() {
tf.positionCaret(location);
}
});
}
}
});
}
public static void main(String[] args) {
launch(args);
}
}
And concerning the Platform.runLater
I added it following this answer Here I don't know why it does not work without it, good luck !
Upvotes: 1