Search code examples
javajavafxcollectionsfxml

Javafx: Reusable collections using FXML


I'd like to bind a single collection to multiple ChoiceBox's in FXML. However the only way I know how is using:

<ChoiceBox fx:id="cb00" prefWidth="150.0" GridPane.rowIndex="0" GridPane.columnIndex="0">
    <items>
        <FXCollections fx:id="test" fx:factory="observableArrayList">
            <String fx:value="1" />
            <String fx:value="2" />
            <String fx:value="3" />
            <String fx:value="4" />
            <String fx:value="5" />
            <String fx:value="6" />
            <String fx:value="7" />
            <String fx:value="8" />
            <String fx:value="9" />
        </FXCollections>
    </items>
</ChoiceBox>

Is it possible to declare the collection in the controller and refer to it in FXML instead of copying the collection for each ChoiceBox?


Solution

  • You can define the items in the controller:

    public class Controller {
    
        private ListProperty<String> choiceBoxItems = new SimpleListProperty(FXCollections.observableArrayList());
    
        public Controller() {
            IntStream.range(1,10).mapToObj(i -> Integer.toString(i))
                .forEach(choiceBoxItems::add);
        }
    
        public ListProperty<String> choiceBoxItemsProperty() {
            return choiceBoxItems ;
        }
    
        public ObservableList<String> getChoiceBoxItems() {
            return choiceBoxItemsProperty().get() ;
        }
    
        public void setComboBoxItems(ObservableList<String> choiceBoxItems) {
            choiceBoxItemsProperty().set(choiceBoxItems) ;
        }
    
        // ...
    }
    

    and then (this is not tested, but I think it will work):

    <ChoiceBox fx:id="cb00" items="${controller.choiceBoxItems}" prefWidth="150.0" GridPane.rowIndex="0" GridPane.columnIndex="0">
    

    See expression binding in the FXML documentation. (It's not actually documented that the controller is available in the FXML namespace with key controller, but I think it is safe to use this.)

    You can also just define the list in the FXML using fx:define:

    <fx:define>
    
        <FXCollections fx:id="choiceBoxItems" fx:factory="observableArrayList">
            <String fx:value="1"/>
            <String fx:value="2"/>
            <String fx:value="3"/>
            <!-- ... -->
        </FXCollections>
    
    </fx:define>
    

    and then refer to it in each choice box:

    <ChoiceBox fx:id="cb00" items="${choiceBoxItems}" prefWidth="150.0" GridPane.rowIndex="0" GridPane.columnIndex="0">