JavaFx: After dialog, two textfields gains focus instead one - javafx-2

following issue:
The instruction in the changeListener leads to the behavior that two TextFields gets Focus after a Dialog.
When Postleitzahl loses focus it open a dialog. If you click OK, just first textfield have to gain the focus . But what really happen is that the textfield below gains focus too.
The method "controlMinChar" sets the minimum amount of numbers. The method setMinCharacter uses the method and uses the focusedProperty
private void setMinCharacter(){
plz.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean lostFocus, Boolean getFocus) {
if(lostFocus){
generalControler.controlMinChar(plz, 5,
(Stage) anchorPane.getScene().getWindow(),
errorMessage);
}
}
});
}
I hope you can help me.
Thank you very much.

Issue is : http://javafx-jira.kenai.com/browse/RT-28363
Workaround :
tf1.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean lostFocus, Boolean getFocus) {
if (lostFocus) {
Platform.runLater(new Runnable() {
#Override
public void run() {
tf1.requestFocus();
}
});
}
}
});

Related

JavaFX TextField: How to "auto-scroll" to right when text overflows

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.
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 !
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
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);
}
});
}

How to thread-safely share an attribute between the beforePhase() and the afterPhase() methods of a PhaseListener?

I need to share an attribute between the beforePhase() and the afterPhase() methods of my PhaseListener, for a same JSF request.
Is the following snippet thread-safe?
public class MyPhaseListener implements PhaseListener {
private MyObject o = null;
#Override
public void beforePhase(PhaseEvent event) {
if (condition) {
o = new MyObject();
}
}
#Override
public void afterPhase(PhaseEvent event) {
if (o != null) {
o.process();
o = null;
}
}
#Override
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
}
If not, what are other solutions?
This is definitely not threadsafe. There's only one phase listener instance applicationwide which is shared across multiple requests. Basically, a phase listener is like an #ApplicationScoped managed bean.
Just set it as a context attribute.
public class MyPhaseListener implements PhaseListener {
#Override
public void beforePhase(PhaseEvent event) {
if (condition) {
event.getFacesContext().setAttribute("o", new MyObject());
}
}
#Override
public void afterPhase(PhaseEvent event) {
MyObject o = (MyObject) event.getFacesContext().getAttribute("o");
if (o != null) {
o.process();
}
}
#Override
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
}
You could use ThreadLocal for this, but it tends to have issues in environments having different classloaders, to name it: memory leak. Be sure to check for that in the given environment...
Also, you should make it sure that if the processing can be interrupted (e.g. exception...) between the beforePhase() and afterPhase() methods, the ThreadLocal should be handled appropriately...
This is what it would look like:
public class MyPhaseListener implements PhaseListener {
//if null is a valid value, no initial setting is needed
private ThreadLocal<Object> myStateObject = new ThreadLocal<Object> ();
#Override
public void beforePhase(PhaseEvent event) {
//might be needed, to guarrantee no residue from an aborted processing is in there
myState.set(null);
if (condition) {
myState.set(<Object representing the state>);
}
}
#Override
public void afterPhase(PhaseEvent event) {
try {
Object stateObject = myState.get();
if (stateObejct!=null) {
//do what you have to
}
} finally {
//to be sure
myState.remove();
}
}
}
In this article the author uses ThreadLocal too...
Also, this article is also a great eye-opener, explaining why not to share mutable instance-level information:
One thing to remember though, is that PhaseListener instances are application-wide Singletons that are referenced by the JSF Lifecycle, which itself is an application-wide Singleton.
EDIT just saw Boolean got updated to Object, adjusted example

JavaFX: How to disable a button for a specific amount of time?

I want to disable a button for a specific time in JavaFX application. Is there any option to do this? If not, is there any work around for this?
Below is my code in application. I tried Thread.sleep, but i know this is not the good way to stop the user from clicking on next button.
nextButton.setDisable(true);
final Timeline animation = new Timeline(
new KeyFrame(Duration.seconds(delayTime),
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
nextButton.setDisable(false);
}
}));
animation.setCycleCount(1);
animation.play();
You could use the simple approach of a thread that provides the relevant GUI calls (through runLater() of course):
new Thread() {
public void run() {
Platform.runLater(new Runnable() {
public void run() {
myButton.setDisable(true);
}
}
try {
Thread.sleep(5000); //5 seconds, obviously replace with your chosen time
}
catch(InterruptedException ex) {
}
Platform.runLater(new Runnable() {
public void run() {
myButton.setDisable(false);
}
}
}
}.start();
It's perhaps not the neatest way of achieving it, but works safely.
You could also be using the Timeline:
final Button myButton = new Button("Wait for " + delayTime + " seconds.");
myButton.setDisable(true);
final Timeline animation = new Timeline(
new KeyFrame(Duration.seconds(delayTime),
new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent actionEvent) {
myButton.setDisable(false);
}
}));
animation.setCycleCount(1);
animation.play();
The method to disable a JavaFX control is:
myButton.setDisable(true);
You can implement the time logic programmatically in any way you wish, either by polling a timer or by having this method invoked in response to some event.
If you have created this button instance through FXML in SceneBuilder, then you should assign the button an fx:id so that its reference is automatically injected into your controller object during the loading of the scene graph. This will make it easier for you to work with in your controller code.
If you have created this button programmatically, then you'll already have its reference available in your code.
Or you could use a Service and bind the running property to the disableProperty of the button do you want to disable.
public void start(Stage stage) throws Exception {
VBox vbox = new VBox(10.0);
vbox.setAlignment(Pos.CENTER);
final Button button = new Button("Your Button Name");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Service<Void> service = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
Thread.sleep(5000);//Waiting time
return null;
}
};
}
};
button.disableProperty().bind(service.runningProperty());
service.start();
}
});
vbox.getChildren().addAll(button);
Scene scene = new Scene(vbox, 300, 300);
stage.setScene(scene);
stage.show();
}
But the Timeline solution given by Uluk Biy, looks more elegant.

How to make checkbox or combobox readonly in JavaFX

How to make checkbox/combobox readonly in javaFX but not disabled.
I tried consuming onAction event but it didn't work.
checkBox.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
event.consume();
}
});
Consuming all events like in code below works but I don't think it's a good solution:
checkBox.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
event.consume();
}
});
checkBox.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEventevent) {
event.consume();
}
});
You can set the check box to disabled but set the the look of it using CSS. If you are using the default style you can make the check box look 'normal' by setting full opacity.
checkbox.setStyle("-fx-opacity: 1");
It is probably a similar deal with the combo box.
You can override method CheckBox#arm() with an empty one:
CheckBox cb = new CheckBox("hi") {
#Override
public void arm() {
// intentionally do nothing
}
};
If you do not want to overwrite the CheckBok class, you can use the selectedProperty.
CheckBox cb = new CheckBox("hi");
cb.selectedProperty().addListener(new NCL());
class NCL implements ChangeListener<Boolean> {
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean old_val, Boolean new_val) {
cb.setSelected(false);
}
}

Can we use create and use custom EventHandler classes in JAVAFX?

I have a question on the Event Handling in JavaFX. As per the tutorial (and other examples that I came across), event handling is carried the following way in JavaFX:
Button addBtn = new Button("Add");
addBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Add Clicked");
}
});
But, I am wondering, if I can "handle" the button click the following way:
Button addBtn = new Button("Add");
addBtn.setOnAction(new addButtonClicked());
where addButtonClicked() is my own Class (with it's own set of methods and functionality) that I have defined and written to handle the actions for the button click.
Is there a way to attach my own event handler classes for buttons in JavaFX?
The EventHandler is an interface class.
So, it should be "implements" not "extends"
private static class AddButtonClicked implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
System.out.println("My Very Own Private Button Handler");
}
}
Sure.
private static class AddButtonClicked extends EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent event) {
System.out.println("My Very Own Private Button Handler");
}
}

Resources