Search code examples
javaeventsjavafxjavafx-8fxml

In JavaFX's FXML, how to declare handlers for custom events?


I'm designing a custom JavaFX node using FXML. This node fires a custom event. And I would like to know how to add an event handler to the custom event in the FXML of the parent of this node.

I created my handler, passed it to the child as an object property and hooked it into the event system via the setEventHandler method. But it throws me an error when the event is fired.

Custom event code :

public class ValueUpdatedEvent extends Event {

    public static final EventType<ActionEvent> VALUE =
            new EventType<>(Event.ANY, "VALUE_UPDATED");

    private float value;

    public ValueUpdatedEvent() {
        super(VALUE);
    }

    public float getValue() {
        return value;
    }

    public void setValue(float value) {
        this.value = value;
    }
}


Child component controller :

public class CharacteristicBar extends Component {

    @FXML
    private JFXTextField field;

    @FXML
    private JFXProgressBar bar;

    @FXML
    private JFXButton plus;

    @FXML
    JFXButton minus;

    private ObjectProperty<EventHandler<ValueUpdatedEvent>> onValueUpdated = new ObjectPropertyBase<EventHandler<ValueUpdatedEvent>>() {
        @Override
        public Object getBean() {
            return CharacteristicBar.this;
        }


        @Override protected void invalidated() {
            setEventHandler(new EventType<>(Event.ANY, "onValueUpdated"), get());
        }


        @Override
        public String getName() {
            return "onValueUpdated";
        }
    };

    private SimpleFloatProperty value = new SimpleFloatProperty();

    private boolean readonly = false;

    public CharacteristicBar() {
        super("CharacteristicBar.fxml");
        value.addListener(
                newValue -> {
                    ValueUpdatedEvent event = new ValueUpdatedEvent();
                    event.setValue(value.get());
                    fireEvent(event);
                }
        );

        bar.progressProperty().bind(this.value);
        if (this.readonly) {
            this.field.setEditable(false);
            this.minus.setVisible(false);
            this.plus.setVisible(false);
        }
    }

    @FXML
    private void handleInput(KeyEvent event) {
        try {
            value.set(Float.parseFloat(field.getText()) / 20f);
        } catch (NumberFormatException exception) {
            field.setText("");
        }
    }

    public float getValue() {
        return value.get() * 20f;
    }

    @FXML
    public void handleClickPlus(ActionEvent event) {
        this.value.set((this.value.get() * 20f + 1f) / 20f);
        this.field.setText(String.valueOf(this.value.get() * 20));
    }

    @FXML
    public void handleClickMinus(ActionEvent event) {
        this.value.set((this.value.get() * 20f - 1f) / 20f);
        this.field.setText(String.valueOf(this.value.get() * 20));
    }

    public boolean isReadonly() {
        return readonly;
    }

    public void setReadonly(boolean readonly) {
        this.readonly = readonly;
        this.field.setEditable(!readonly);
        this.minus.setVisible(!readonly);
        this.plus.setVisible(!readonly);
    }

    public EventHandler<ValueUpdatedEvent> getOnValueUpdated() {
        return onValueUpdated.get();
    }

    public ObjectProperty<EventHandler<ValueUpdatedEvent>> onValueUpdatedProperty() {
        return onValueUpdated;
    }

    public void setOnValueUpdated(EventHandler<ValueUpdatedEvent> onValueUpdated) {
        this.onValueUpdated.set(onValueUpdated);
    }
}

Parent's FXML :

<CharacteristicBar fx:id="courageBar" onBarValueChanged="#handleChangeCou" 
GridPane.columnIndex="1" GridPane.rowIndex="7"/>

Handler in parent's controller:

    @FXML
    public void handleChangeCou(ValueUpdatedEvent event){
        System.out.println(event.getValue());
    }

Still, my event handler isn't called.

Do you guys have any clue on how to hook my handler with the event system ?

Thanks in advance


Solution

  • I could not get the custom event to work but instead I used properties to achieve my goal. Maybe it's intendend this way in JavaFX