I have a controller class in a JavaFX program which is handling numerous Nodes. I created a method addEventListeners
which looks like:
cleanButton.setOnAction(e -> {
...
});
advSett.setOnAction(e -> {
...
});
imageLoaderItem.setOnAction(e -> {
...
});
outputButton.setOnAction(e -> {
...
});
And so on for each element handled by the controller. This method is occupying 300 lines of code making the controller class quite messy. I was wondering, is there a cleaner way of adding the listeners?
This answer is complementary and additional to Vinz's answer. The information in this answer can be used in combination with the suggestions suggested in that answer or separately.
As noted in the Introduction to FXML documentation, you can directly associate events from FXML to Java or script code, using the #
prefix on the event name in FXML.
Using the #
injection method is a bit more succinct than invoking setOnAction
. It is a matter of stylistic or personal preference as to which method to use. Both approaches are valid and the results are identical. Neither way is "correct" or "incorrect".
Paraphrasing from the documentation, given this definition:
<VBox fx:controller="com.foo.MyController"
xmlns:fx="http://javafx.com/fxml">
<children>
<Button text="Click Me!" onAction="#handleButtonAction"/>
</children>
</VBox>
You can write:
package com.foo;
import javafx.event.ActionEvent;
public class MyController {
public void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
}
}
Or, if you prefer using @FXML
and not public methods, you can write:
package com.foo;
import javafx.fxml.FXML;
import javafx.event.ActionEvent;
public class MyController {
@FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
}
}
Further, the event parameter is optional, so you can just leave it out if not needed, and write:
package com.foo;
public class MyController {
public void handleButtonAction() {
System.out.println("You clicked me!");
}
}
Any of the above methods is equivalent to writing (after also adding an fx:id="button"
attribute in the FXML):
package com.foo;
import javafx.fxml.FXML;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
public class MyController implements Initializable {
@FXML private Button button;
@FXML
protected void initialize()
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("You clicked me!");
}
});
}
}
If multiple actions should have the same handler, you can reference the same handler name and implementation multiple times in the FXML file, like below:
<VBox fx:controller="com.foo.MyController"
xmlns:fx="http://javafx.com/fxml">
<children>
<Button text="Click Me!" onAction="#handleButtonAction"/>
<Button text="Click Me Too!" onAction="#handleButtonAction"/>
</children>
</VBox>
Complementary question: