JavaFX : ChangeListener to get the resolution of screen on mouse released - javafx

How do I get the resolution of the screen application (during resize) but only once the mouse has been released ?
I've looked around, but I found nothing. I've done this :
scene.widthProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
ConfigBusiness.getInstance().setScreenWidth(newValue.intValue());
}
});
scene.heightProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
ConfigBusiness.getInstance().setScreenHeight(newValue.intValue());
}
});
But as you expect, everytime the width / height changes, it calls the function to save the value (in my case, in the registry, which results in many calls).
Is there a way to get the value only when the mouse button has been released ? Or maybe use another kind of listener (setOnMouseDragRelease or something like that) ?
EDIT : I want the user to be able to resize the application window, and once he releases the mouse button after resizing I would like to trigger an event (and not during the whole resizing process).
Thanks
EDIT 2 : Following a bit the idea of #Tomas Bisciak, I came up with this idea.
scene.widthProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if(!widthHasChanged()){
setWidthChanged(true);
System.out.println("Width changed");
}
}
});
scene.heightProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if(!heightHasChanged()){
setHeightChanged(true);
System.out.println("Height changed");
}
}
});
scene.addEventFilter(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if(widthHasChanged()){
ConfigBusiness.getInstance().setScreenWidth(scene.getWidth());
System.out.println("Width changed > release");
setWidthChanged(false);
}
if(heightHasChanged()){
ConfigBusiness.getInstance().setScreenHeight(scene.getHeight());
System.out.println("Height changed > release");
setHeightChanged(false);
}
}
});
I flagged the changes done during the resizing process (with the help of widthProperty and heightProperty) and set them to true if changed, and then when releasing the mouse, I set the values if they have changed.
The problem is that the last event MOUSE_RELEASED is not triggered. I see the output from the changeListeners but not the eventFilter. Any ideas ?

Hook listener onto scene Handle mouse event anywhere with JavaFX (use MouseEvent.MOUSE_RELEASED) and on mouse release write values of the setScreenHeight/width(on every mouse release ),
if you want to only write values when drag happened with intention of resize , use boolean flag in change() "flag=true on change" methods to indicate that change has started, aferwards on mouse release just write values wherever you want and set flag to (flag=false).

If you want every time the mouse is released to get the resolution of the Monitor Screen here is the code:
Assuming you have the code for the Stage and Scene you can add a Listener for MouseReleased Event like this:
public double screenWidth ;
public double screenHeight;
.......
scene.setOnMouseReleased(m->{
screenWidth = Screen.getPrimary().getBounds().getWidth();
screenHeight = Screen.getPrimary().getBounds().getHeight();
});
......
In case you have an undecorated window that you resize it manually
when the mouse is dragged i recommend you using setOnMouseDragged();
Assuming that you are doing the above this code for moving the window
manually can be useful:
public int initialX;
public int initialY;
public double screenWidth = Screen.getPrimary().getBounds().getWidth() ;
public double screenHeight = Screen.getPrimary().getBounds().getHeight();
setOnMousePressed(m -> {
if (m.getButton() == MouseButton.PRIMARY) {
if (m.getClickCount() == 1) { // one Click
setCursor(Cursor.MOVE);
if (window.getWidth() < screenWidth ) {
initialX = (int) (window.getX() - m.getScreenX());
initialY = (int) (window.getY() - m.getScreenY());
} else
setFullScreen(false);
} else if (m.getClickCount() == 2) // two clicks
setFullScreen(true);
}
});
setOnMouseDragged(m -> {
if (window.getWidth() < screenWidth && m.getButton() == MouseButton.PRIMARY) {
window.setX(m.getScreenX() + initialX);
window.setY(m.getScreenY() + initialY);
}
});
setOnMouseReleased(m -> setCursor(Cursor.DEFAULT));

I finally found a way to accomplish "more or less" what I wanted. Here is the code for those who are looking for how to do it.
ChangeListener<Number> resizeListener = new ChangeListener<Number>() {
Timer timer = null; // used to schedule the saving task
final long delay = 200; // the delay between 2 changes
TimerTask task = null; // the task : saves resolution values
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
// cancels the old task as a new one has been queried
// at every change, we cancel the old task and start a new one
if(task != null) task.cancel();
// reset of the timer
if(timer == null) timer = new Timer();
task = new TimerTask() {
#Override
public void run() {
ConfigBusiness.getInstance().setScreenWidth(scene.getWidth());
ConfigBusiness.getInstance().setScreenHeight(scene.getHeight());
// stopping the timer once values are set
timer.cancel();
timer = null;
// stopping the task once values are set
task.cancel();
task = null;
}
};
timer.schedule(task, delay);
}
};
scene.widthProperty().addListener(resizeListener);
scene.heightProperty().addListener(resizeListener);
I added some comments just to help understanding the way it works. During resizing, a timer schedules a task to retrieve the width / height of the window and is started.
If another changes incomes, then the task is "reset" in order to get only the last values set.
Once the values are retrieved, it is important to clear the timer and the task, else threads will continue running.
Thanks to all who gave me hints on how to do it, hope this helps !

Related

JavaFX Spinner change is slow with click and hold of mouse button

The speed of Spinner update is slow when I click and hold the up/down arrow buttons. Is there a way to increase the change speed?
When I click, click, click with the mouse, the spinner values change as fast as I click. It also changes fast if I use the up/down arrows on the keyboard for each key press or if I hold down the up/down arrow keys. I want the values to change that fast when I click and hold on the arrow buttons.
Anyone know a way to do that?
The SpinnerBehavior of the SpinnerSkin triggers updates every 750 ms. Unfortunately there is no way to simply set/modify this behavour without using reflection to access private members. Therefore the only way to do this without reflection is using event filters to trigger the updates at a faster rate:
private static final PseudoClass PRESSED = PseudoClass.getPseudoClass("pressed");
#Override
public void start(Stage primaryStage) {
Spinner<Integer> spinner = new Spinner(Integer.MIN_VALUE, Integer.MAX_VALUE, 0);
class IncrementHandler implements EventHandler<MouseEvent> {
private Spinner spinner;
private boolean increment;
private long startTimestamp;
private static final long DELAY = 1000l * 1000L * 750L; // 0.75 sec
private Node button;
private final AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
if (now - startTimestamp >= DELAY) {
// trigger updates every frame once the initial delay is over
if (increment) {
spinner.increment();
} else {
spinner.decrement();
}
}
}
};
#Override
public void handle(MouseEvent event) {
if (event.getButton() == MouseButton.PRIMARY) {
Spinner source = (Spinner) event.getSource();
Node node = event.getPickResult().getIntersectedNode();
Boolean increment = null;
// find which kind of button was pressed and if one was pressed
while (increment == null && node != source) {
if (node.getStyleClass().contains("increment-arrow-button")) {
increment = Boolean.TRUE;
} else if (node.getStyleClass().contains("decrement-arrow-button")) {
increment = Boolean.FALSE;
} else {
node = node.getParent();
}
}
if (increment != null) {
event.consume();
source.requestFocus();
spinner = source;
this.increment = increment;
// timestamp to calculate the delay
startTimestamp = System.nanoTime();
button = node;
// update for css styling
node.pseudoClassStateChanged(PRESSED, true);
// first value update
timer.handle(startTimestamp + DELAY);
// trigger timer for more updates later
timer.start();
}
}
}
public void stop() {
timer.stop();
button.pseudoClassStateChanged(PRESSED, false);
button = null;
spinner = null;
}
}
IncrementHandler handler = new IncrementHandler();
spinner.addEventFilter(MouseEvent.MOUSE_PRESSED, handler);
spinner.addEventFilter(MouseEvent.MOUSE_RELEASED, evt -> {
if (evt.getButton() == MouseButton.PRIMARY) {
handler.stop();
}
});
Scene scene = new Scene(spinner);
primaryStage.setScene(scene);
primaryStage.show();
}
I modified the answer of fabian a little bit to decrease the speed of the spinner while holding mouse down:
private int currentFrame = 0;
private int previousFrame = 0;
#Override
public void handle(long now)
{
if (now - startTimestamp >= initialDelay)
{
// Single or holded mouse click
if (currentFrame == previousFrame || currentFrame % 10 == 0)
{
if (increment)
{
spinner.increment();
}
else
{
spinner.decrement();
}
}
}
++currentFrame;
}
And after stopping the timer we adjust previousFrame again:
public void stop()
{
previousFrame = currentFrame;
[...]
}
A small improvement to Fabian's answer. Making the following mod to the MOUSE_RELEASED addEventerFilter will stop a NullPointerException caused when clicking the textfield associated with the spinner. Cheers Fabian!
spinner.addEventFilter(MouseEvent.MOUSE_RELEASED, evt -> {
Node node = evt.getPickResult().getIntersectedNode();
if (node.getStyleClass().contains("increment-arrow-button") ||
node.getStyleClass().contains("decrement-arrow-button")) {
if (evt.getButton() == MouseButton.PRIMARY) {
handler.stop();
}
}
});
An alternative to changing the update speed might in some cases be adjusting the amount by which the value increments/decrements per update.
SpinnerValueFactory.IntegerSpinnerValueFactory intFactory =
(SpinnerValueFactory.IntegerSpinnerValueFactory) spinner.getValueFactory();
intFactory.setAmountToStepBy(100);
Reference: http://news.kynosarges.org/2016/10/28/javafx-spinner-for-numbers/

JavaFX - Progress properties don't work?

I'm trying to get the progress value of my Picture Viewer when another picture is loading. I've tried two simple ways to do it, but it didn't work out for me.
First I was using the progressProperty from the Image class:
public boolean nextImageClicked()
{
if(PICTURE_INDEX < picturePaths.size() - 1)
{
String path = picturePaths.get(PICTURE_INDEX + 1).toURI().toString();
Image newImage = new Image(path);
newImage.progressProperty().addListener((observable, oldValue, newValue) -> System.out.println("Current progress: "+newValue));
GUI.getImageView().setImage(newImage);
adjustImageViewBounds();
PICTURE_INDEX += 1;
return true;
}
else return false;
}
It didn't print out anything on the console because the progress value doesn't change bizarrely. So I've tried to put all the work stuff in a Task<Void> and getting the progress value through the Task:
public boolean nextClicked()
{
if(PICTURE_INDEX < picturePaths.size() - 1)
{
Task<Void> task = new Task<Void>()
{
#Override protected Void call() throws Exception
{
String path = picturePaths.get(PICTURE_INDEX + 1).toURI().toString();
Image newImage = new Image(path);
GUI.getImageView().setImage(newImage);
adjustImageViewBounds();
PICTURE_INDEX += 1;
return null;
}
};
task.setOnRunning(e -> System.out.println(task.getProgress()));
task.progressProperty().addListener((observable, oldValue, newValue) ->
{
System.out.println(newValue);
});
task.run();
return true;
}
else return false;
}
Also didn't work out as hoped.
task.setOnRunning(e -> System.out.println(task.getProgress()));
I implemented this to see the default value, it printed out "-1".
What have I to change to let the console return single progress values like "0.1", "0.14" ?
You need the Image to load in the background, so that the call to the constructor returns before the image is completely loaded. By default, it will block until it is loaded (so the progress property will be 1 by the time you add the listener to it):
public boolean nextImageClicked()
{
if(PICTURE_INDEX < picturePaths.size() - 1)
{
String path = picturePaths.get(PICTURE_INDEX + 1).toURI().toString();
// note additional parameter:
Image newImage = new Image(path, true);
newImage.progressProperty().addListener((observable, oldValue, newValue) -> System.out.println("Current progress: "+newValue));
GUI.getImageView().setImage(newImage);
adjustImageViewBounds();
PICTURE_INDEX += 1;
return true;
}
else return false;
}
For a Task's progress to change, you need to explicitly call updateProgress(...) on the task. The only way to know what to pass in would be to observe the image's progress and pass it to the task's progress, so you would just have a more convoluted version of the code above. This is not a good use case for a task, since Image already supports background loading out of the box.
Don't try to do this on your own. You've got no idea, how much of the image has been loaded, unless you find the size of the image before loading and load the image from a steam observing the progress of the stream, which would be unnecessarily complicated. BTW: The Image constructor you use returns when the image is completely loaded. You can specify the image to be loaded asynchronically by using the right constructor however. Image provides a progress property to observe the loading progress:
#Override
public void start(Stage primaryStage) {
ImageView iv = new ImageView();
ProgressBar pb = new ProgressBar();
Button btn = new Button("Load Image");
btn.setOnAction((ActionEvent event) -> {
// ca. 6 MB image loaded from web
Image image = new Image("http://eoimages.gsfc.nasa.gov/images/imagerecords/79000/79793/city_lights_africa_8k.jpg", true);
pb.progressProperty().bind(image.progressProperty());
iv.setImage(image);
});
ScrollPane sp = new ScrollPane(iv);
VBox.setVgrow(sp, Priority.ALWAYS);
VBox root = new VBox(btn, pb, sp);
root.setFillWidth(true);
Scene scene = new Scene(root);
primaryStage.setMaximized(true);
primaryStage.setScene(scene);
primaryStage.show();
}

How to wait for user's action in JavaFX (in the same stage)

Do you know how to wait for the user's input in a for loop? I don't mean the showAndWait() method, because I am not opening a new dialogue stage for the user. So for example, each round of the for loop should be waiting for the user to push a button before going ahead with the next round.
How is it possible? Many thanks!
UPDATE:
Now it came to my mind, that it would work with a while(buttonNotPressed){} but is it a good solution? I mean the while loop is running in this case as crazy until the user won't push the button. Or doest it work somehow similarly with wait methods?
Imagine it as a session:
User starts session with handleStart() You give the user 5 questions, one after one. In every iteration, the user can answer the upcoming question and he can save or submit the answer by handleSaveButton() You process the answer as you want, and go ahead with the next iteration. The point is, that the iteration must stop, until the save button hasn't been pressed.
Don't do it like that. The FX toolkit, like any event-driven GUI toolkit, already implements a loop for the purposes of rendering the scene graph and processing user input each iteration.
Just register a listener with the button, and do whatever you need to do when the button is pressed:
button.setOnAction(event -> {
// your code here...
});
If you want the action to change, just change the state of some variable each time the action is performed:
private int round = 0 ;
// ...
button.setOnAction(event -> {
if (round < 5) {
System.out.println("Round "+round);
System.out.println("User's input: "+textArea.getText());
round++ ;
}
});
I recently ran into a similar problem where I wanted something to be executed with an interval (if that's what you mean), until the user fired an event. I found 3 ways to do this:
UPDATE
You should use the stop/cancel method for the custom runnable and timer or else the thread will still be running when you exit the application. Timeline seems do it by itself.
Using a Timer:
Timer timer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
System.out.println("Printed every second.");
}
};
timer.scheduleAtFixedRate(task, 0, 1000);
//timer.cancel();
With a TimeLine:
Timeline tl = new Timeline(new KeyFrame(Duration.millis(1000), e -> {
System.out.println("Timeline");
}));
tl.setCycleCount(Timeline.INDEFINITE);
tl.play();
//tl.stop();
Or making your own runnable class:
public class Runner implements Runnable {
private final Thread thread = new Thread(this);
private boolean run;
#Override
public void run() {
while(run) {
try {
System.out.println("Printed from loop");
Thread.sleep(1000);
} catch (InterruptedException e) {
run = false;
}
}
}
public void start() {
run = true;
thread.start();
}
public void stop() {
if(run) {
thread.interrupt();
System.out.print("Thread has stopped.");
}
}
}
And then when a person clicks fx. a button the event would stop using the example James_D posted:
Button btn = new Button("Button");
btn.setOnAction(e -> {
timer.cancel();
tl.stop();
runner.stop();
});
In my case, for inside for, had to create 2 index in class, use:
//start method
Timer timer = new Timer();
TimerTask task = new TimerTask()
{
public void run()
{
Platform.runLater(()->{
//... code to run after time, calling the same mehtod, with condition to stop
});
}
};
timer.schedule(task, time);
//end method
Had to use recursive method, incrementing the index with conditions, cause the tasks were been schedule all at the same time, without wait time.
I do not know if it is rigth, but was the solution that i found.
Hope it helps.
ALTERNATIVE SOLUTION W/O PAUSING:
I'm creating a game where I want the user to pick the game difficulty before the game starts. Instead of trying to pause the program midway through, I just put the next step of the code in a separate method which you call once a button is clicked:
private static difficulty;
public static void main(String[] args) {
try {
Application.launch(args);
} catch (UnsupportedOperationException e) {
}
}
public void start(Stage startStage) {
HBox buttons = new HBox();
Button easyButton = new Button("Easy");
Button mediumButton = new Button("Medium");
Button hardButton = new Button("Hard");
buttons.getChildren().addAll(easyButton, mediumButton, hardButton);
buttons.setAlignment(Pos.CENTER);
hbox.getChildren().addAll(buttons);
Scene startScene = new Scene(buttons, 200, 200);
startStage.setScene(startScene);
startStage.show(); // MENU
EventHandler<ActionEvent> playEasy = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
difficulty = 1; // SET DIFFICULTY
startStage.close(); // CLOSE MENU
play(); // RUN GAME ON EASY
}
};
EventHandler<ActionEvent> playMedium = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
difficulty = 2; // SET DIFFICULTY
startStage.close(); // CLOSE MENU
play(); // RUN GAME ON MEDIUM
}
};
EventHandler<ActionEvent> playHard = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
difficulty = 3; // SET DIFFICULTY
startStage.close(); // CLOSE MENU
play(); // RUN GAME ON HARD
}
};
easyButton.setOnAction(playEasy);
mediumButton.setOnAction(playMedium);
hardButton.setOnAction(playHard);
}
public void play() {
// WRITE GAME CODE HERE
}
To solve your specific problem, you could probably pass the startStage into the play method and then just update the scene there...but regardless I do hope this helps someone whos having trouble on how to use buttons! :)

How to filter out JavaFX Slider adjusting events [duplicate]

I am trying to catch the events on the JavaFX Slider especially the one which indicates that the drag stopped and was released. At first I used the valueProperty with mock-up code like this
slider.valueProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> ov, Number oldValue, Number newValue) {
log.fine(newValue.toString());
}
});
but with this it update too often. So I searched within SceneBuilder and the API and found some interessting like
slider.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
#Override
public void handle(MouseDragEvent event) {
System.out.println("setOnMouseDragReleased");
}
});
but they never get fired. There only some like setOnMouseReleased I get some output, but this for example count for the whole Node like the labels etc.
So my question is, which is the correct hook to know the value is not changing anymore (if possible after release of the mouse like drag'n'drop gesture) and maybe with a small example to see its interfaces working.
Add a change listener to the slider's valueChangingProperty to know when the slider's value is changing, and take whatever action you want on the value change.
The sample below will log the slider's value when it starts to change and again when it finishes changing.
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class SliderChangeLog extends Application {
private final ListView<String> startLog = new ListView<>();
private final ListView<String> endLog = new ListView<>();
#Override public void start(Stage stage) throws Exception {
Pane logsPane = createLogsPane();
Slider slider = createMonitoredSlider();
VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.setPadding(new Insets(10));
layout.getChildren().setAll(
slider,
logsPane
);
VBox.setVgrow(logsPane, Priority.ALWAYS);
stage.setTitle("Slider Value Change Logger");
stage.setScene(new Scene(layout));
stage.show();
}
private Slider createMonitoredSlider() {
final Slider slider = new Slider(0, 1, 0.5);
slider.setMajorTickUnit(0.5);
slider.setMinorTickCount(0);
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
slider.setMinHeight(Slider.USE_PREF_SIZE);
slider.valueChangingProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(
ObservableValue<? extends Boolean> observableValue,
Boolean wasChanging,
Boolean changing) {
String valueString = String.format("%1$.3f", slider.getValue());
if (changing) {
startLog.getItems().add(
valueString
);
} else {
endLog.getItems().add(
valueString
);
}
}
});
return slider;
}
private HBox createLogsPane() {
HBox logs = new HBox(10);
logs.getChildren().addAll(
createLabeledLog("Start", startLog),
createLabeledLog("End", endLog)
);
return logs;
}
public Pane createLabeledLog(String logName, ListView<String> log) {
Label label = new Label(logName);
label.setLabelFor(log);
VBox logPane = new VBox(5);
logPane.getChildren().setAll(
label,
log
);
logPane.setAlignment(Pos.TOP_LEFT);
return logPane;
}
public static void main(String[] args) { launch(args); }
}
There could be times when you want to know when the user is moving the slider versus the slider value changing due to a binding to a property. One example is a slider that is used on a media player view to show the media timeline. The slider not only displays the time but also allows the user to fast forward or rewind. The slider is bound to the media player's current time which fires the change value on the slider. If the user moves the slider, you may want to detect the drag so as to stop the media player, have the media player seek to the new time and resume playing. Unfortunately the only drag event that seems to fire on the slider is the setOnDragDetected event. So I used the following two methods to check for a slider drag.
slider.setOnDragDetected(new EventHandler<Event>() {
#Override
public void handle(Event event) {
currentPlayer.pause();
isDragged=true;
}
});
slider.setOnMouseReleased(new EventHandler<Event>() {
#Override
public void handle(Event event) {
if(isDragged){
currentPlayer.seek(Duration.seconds((double) slider.getValue()));
currentPlayer.play();
isDragged=false;
}
}
});
jewelsea's answer was very helpful for setting me on the right track, however if "snapToTicks" is on, undesired behavior results. The "end" value as captured by jewelsea's listener is before the snap takes place, and the post-snap value is never captured.
My solution sets a listener on value but uses valueChanging as a sentinel. Something like:
slider.valueProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(
ObservableValue<? extends Number> observableValue,
Number previous,
Number now) {
if (!slider.isValueChanging()
|| now.doubleValue() == slider.getMax()
|| now.doubleValue() == slider.getMin()) {
// This only fires when we're done
// or when the slider is dragged to its max/min.
}
}
});
I found that checking for the max and min value was necessary to catch the corner case where the user drags the slider all the way past its left or right bounds before letting go of the mouse. For some reason, that doesn't fire an event like I'd expect, so this seems like an okay work-around.
Note: Unlike jewelsea, I'm ignoring the starting value for the sake of simplicity.
Note 2: I'm actually using ScalaFX 2, so I'm not sure if this Java translation compiles as-written.

JFXtras - How to add Change Listener to CalendarTextField?

how can I listen to a change in the CalendarTextField in JFXtras? For example a new choosen date from the picker-menu or a typed-in date?
date.addEventFilter(MouseEvent.ANY, new EventHandler<Event>() {
#Override
public void handle(Event arg0) {
System.out.println("EVENT");
}
});
gives me every movement of the mouse within the field. I didn't find another eventType that makes sense.
I also thought about adding this event filter in the window and check the selected date at every click in the window. But that can't be the right way.
Alright, found it here:
date.valueProperty().addListener(new ChangeListener<Calendar>() {
#Override
public void changed(
ObservableValue<? extends Calendar> observableValue,
Calendar oldValue, Calendar newValue) {
System.out.println(oldValue + " -> " + newValue);
}
});
I didn't realize that in FX a listener has to be set to the property, not to the component like in Swing.
I have redesigned a calendar component in a control with FXML, for the picker-menu I use the XCalendarPicker and I add a changelistener to it calendar() (who is a property). And when a date is changed I update my textfield with the new Date
final XCalendarPicker calendarPicker = new XCalendarPicker();
final ChangeListener<Calendar> calendarListener = new ChangeListener<Calendar>() {
#Override
public void changed(ObservableValue<? extends Calendar> observable, Calendar oldValue, Calendar newValue) {
Date date = newValue.getTime();
setDate(date);
}
};
calendarPicker.calendar().addListener(calendarListener);

Resources