zephirus
zephirus

Reputation: 391

How can I access multiple ToggleButtons created in a class?

I have a GridPane (6x9) made with SceneBuilder. Inside that GridPane I created 50 ToggleButtons in my controller with the following code:

@FXML
private void initialize() {
    Font numbersFont = new Font("Arial", 10);
    for (int y = 0; y < 9; y++){
        for (int x = 1; x < 7; x++) {
            Integer buttonId = (y * 6) + x;
            if (buttonId == 51) {break;}
            ToggleButton tb = new ToggleButton(Integer.toString(buttonId));
            tb.setId("tb_" + Integer.toString(buttonId));
            tb.setFont(numbersFont);
            tb.setPrefSize(27, 27);
            tb.setAlignment(Pos.CENTER);
            tb.selectedProperty().addListener(new ChangeListener<Boolean>() {
                @Override
                public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                    boolean isSelected = newValue;
                    System.out.println(isSelected);
                }
            });
            numbersGrid.add(tb, x - 1, y);
        }
    }
}

In my MainApp.java I've created an array of integers:

private ObservableIntegerArray selectedNumbers = FXCollections.observableIntegerArray();

I have two questions.

  1. I want is to update the selectedNumbers array with the numbers of the ToggleButtons that are pressed. For example, if I press button 1, 13 and 25, the array should be [1, 13, 25]. When I "turn off" a button, that number should be removed from the array. How can I add and remove those values? Where should I have this code? Inside the initialize method?

  2. I have a method that randomly picks N numbers from the 50 available (1 to 50). When the user clicks a button, I want the ToggleButtons with that number to be "turned on". I know how to do a loop but how can I access the buttons? I mean, I named them tb_1, tb_2 and so on. So... how can I call them?

Thanks!

Upvotes: 0

Views: 490

Answers (2)

James_D
James_D

Reputation: 209330

I would recommend creating and exposing an ObservableSet<Integer> in the controller, representing the set of selected toggles. This is pretty straightforward to do using the code you already have:

public class MyController {

    private final ObservableSet<Integer> selectedToggles = FXCollections.observableSet();
    public final ObservableSet<Integer> getSelectedToggles() {
        return selectedToggles ;
    }

    @FXML
    private void initialize() {
        Font numbersFont = new Font("Arial", 10);
        for (int y = 0; y < 9; y++){
            for (int x = 1; x < 7; x++) {
                Integer buttonId = (y * 6) + x;
                if (buttonId == 51) {break;}
                ToggleButton tb = new ToggleButton(Integer.toString(buttonId));
                tb.setId("tb_" + Integer.toString(buttonId));
                tb.setFont(numbersFont);
                tb.setPrefSize(27, 27);
                tb.setAlignment(Pos.CENTER);
                tb.selectedProperty().addListener(new ChangeListener<Boolean>() {
                    @Override
                    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                        boolean isSelected = newValue;
                        if (isSelected) {
                            selectedToggles().add(buttonId);
                        } else {
                            selectedToggles().remove(buttonId);
                        }
                    }
                });
                numbersGrid.add(tb, x - 1, y);
            }
        }
    }

}

Then in your main application (or wherever you need) you can retrieve the observable set and register a listener with it:

FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/fxml"));
Parent parent = loader.load();
MyController controller = loader.getController();
controller.getSelectedToggles().addListener((Change<? extends Integer> change) -> {
    ObservableSet<Integer> selectedToggles = controller.getSelectedToggles();
    // process selected ids...
});

To be able to manipulate the toggle buttons state (e.g. to initialize them to your random values), you can make each button respond to changes in the observable set. In the code where you create the toggle button (in the controller), add this:

// existing code:
ToggleButton tb = new ToggleButton(Integer.toString(buttonId));
tb.setId("tb_" + Integer.toString(buttonId));

// respond to changes in observable set:
selectedToggles.addListener((Change<? extends Integer> change) -> 
    tb.setSelected(selectedToggles.contains(buttonId)));

Then you can manipulate the toggle button state with

List<Integer> initiallySelected = ... ;
controller.getSelectedToggles().clear();
controller.getSelectedToggles().addAll(initiallySelected);

Upvotes: 1

Stephan Bijzitter
Stephan Bijzitter

Reputation: 4595

1: Don't use arrays like that. If doing something like that, use an ArrayList! I suggest using an array with 50 boolean indices boolean[] myArray = boolean[50]; and setting the indices true or false.

You would have it loop over the entire array and use the array's values on initialization. You then add an event listener to the buttons to run it again whenever the user toggles a value.

2: Add all your buttons to an array and get them by index. As they will be referenced (and not copied) this will have no impact on performance, perhaps the memory usage increases by a few kilobits, but that'll be it.

Upvotes: 0

Related Questions