I have 10 toggle buttons say tb1, tb2,.. and so on. Each one has one user data attached to it. I need to attach a listener for a action (sequence of instructions) to be performed when button are clicked and unclicked. I would prefer the listener to be generic (usable for all the buttons).
The problem I am facing is that, how can I access the user data of clicked button in the listener.Please help through this.
@FXML
private ToggleButton tb1;
@FXML
private ToggleButton tb2;
String cpuLoad1 ="D:/myWorkspace/TestAttacks/input_folder/app_debug.apk";
String cpuLoad2 = "D:/myWorkspace/TestAttacks/input_folder/cpuLoad1.apk";
public void initialize(){
tb1.setUserData(cpuLoad1);
tb2.setUserData(cpuLoad2);
ChangeListener clt1 = new ChangeListener() {
public void changed(ObservableValue ov,
Object toggle, Object new_toggle){
if(new_toggle.equals(true)){
/*how can I acces togglebutton userdata here.
*I would like to pass it as argument to this class object*/
App load = new App(buttonClicked.getUserData()); //button clicked could tb1 or tb2
load.installApp();
load.launchApp();
}else{
System.out.println("OFF");
/*how can I acces togglebutton userdata here.
*I would like to pass it as argument to this class object.*/
App load = new App(buttonClicked.getUserData());
load.unInstallApp();
}
}
};
tb1.selectedProperty().addListener(clt1);
tb2.selectedProperty().addListener(clt1);
}
You have several options.
Option1: Collect the ToggleButton
s into a collection and use the reference directly in the listener:
List<ToggleButton> toggles = new ArrayList<>(Arrays.asList(tb1, tb2));
for(ToggleButton toggle:toggles)
toggle.selectedProperty().addListener((observable, oldValue, newValue) ->
System.out.println(toggle.getText() + " - Selected: " + toggle.isSelected() + "; UserData: " + toggle.getUserData()));
Option2: You can use the onActionProperty
:
tb1.setOnAction(e -> {
ToggleButton toggle = (ToggleButton) e.getSource();
System.out.println(toggle.getText() + " - Selected: " + toggle.isSelected()
+ "; UserData: " + toggle.getUserData());
});
Option3: If you need to store the listeners, you can implement you own ChangeListener
.
public class Toggles extends Application {
public static void main(String[] args) { launch(args); }
@Override
public void start(Stage primaryStage) throws Exception {
VBox vBox = new VBox();
for (int i = 0; i < 20; i++) {
ToggleButton tb = new ToggleButton("ToggleButton" + i);
tb.setUserData("UserData" + i);
tb.selectedProperty().addListener(new ToggleButtonSourcedChangeListener(tb));
vBox.getChildren().add(tb);
}
Scene scene = new Scene(new BorderPane(vBox), 320, 240);
primaryStage.setScene(scene);
primaryStage.show();
}
private abstract static class SourcedChangeListener<T extends Node> implements ChangeListener<Boolean> {
T source;
SourcedChangeListener(T source) {
this.source = source;
}
}
private static class ToggleButtonSourcedChangeListener extends SourcedChangeListener<ToggleButton> {
ToggleButtonSourcedChangeListener(ToggleButton source) {
super(source);
}
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
System.out.println(source.getText() + " - Selected: " + source.isSelected()
+ "; UserData: " + source.getUserData());
}
}
}
In this SSCE I created an abstract SourceChangeListener
that can be extended by concrete implementations. The intention behind the generic parameter <T extends Node>
is to avoid casts.
When you execute this code, and click on the toggles, the output will be like:
ToggleButton4 - Selected: true; UserData: UserData4
ToggleButton5 - Selected: true; UserData: UserData5
ToggleButton4 - Selected: false; UserData: UserData4
ToggleButton8 - Selected: true; UserData: UserData8
ToggleButton5 - Selected: false; UserData: UserData5
ToggleButton2 - Selected: true; UserData: UserData2
I would propose one of the options that use the selectedProperty
as the onActionProperty
will change only if the button was pressed (by mouse, touch or key) or if you programatically call the fire()
method. The other two options will work always, even if you change the selected state programatically.