问题描述:

I've made a configuration panel for a JavaFX application. I managed to create a dynamic change listener as follows:

public class InputMaskChecker implements ChangeListener<String> {

public static final String NUMERIC = "^[0-9]*$";

public static final String TEXTONLY = "^\\w*$";

public static final String PASSWORD = "^[\\w\\+\\!\\?\\-\\$\\&\\%£]+$";

public static final String DATASOURCE = "^([a-zA-Z]+:){3}@([a-zA-Z0-9]+:)+[a-zA-Z0-9]+$";

public static final String TCPPORT = "^(6553[0-5]|655[0-2]\\d|65[0-4]\\d\\d|6[0-4]\\d{3}|[1-5]\\d{4}|[2-9]\\d{3}|1[1-9]\\d{2}|10[3-9]\\d|102[4-9])$";

private static final String STYLE = "-fx-effect: dropshadow(gaussian, red, 4, 0.0, 0, 0);";

public final BooleanProperty erroneous = new SimpleBooleanProperty(false);

private final String mask;

private final int max_lenght;

private final TextField control;

public InputMaskChecker(String mask, TextField control) {

this.mask = mask;

this.max_lenght = 0;

this.control = control;

}

public InputMaskChecker(String mask, int max_lenght, TextField control) {

this.mask = mask;

this.max_lenght = max_lenght;

this.control = control;

}

@Override

public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {

erroneous.setValue(!newValue.matches(mask) || ((max_lenght > 0) ? newValue.length() > max_lenght : false) || newValue.length() == 0);

control.setStyle( erroneous.get() ? STYLE : "-fx-effect: null;");

}

}

using it within my controller like this:

field1.textProperty().addListener(new InputMaskChecker(InputMaskChecker.DATASOURCE, field1));

field2.textProperty().addListener(new InputMaskChecker(InputMaskChecker.TEXTONLY, field2));

field3.textProperty().addListener(new InputMaskChecker(InputMaskChecker.PASSWORD, field3));

field4.textProperty().addListener(new InputMaskChecker(InputMaskChecker.NUMERIC, 1, field4));

It works as expected with a glitch: I'd like to have my SAVE button on the main controller react to listeners in a way that it is disabled if a field has an error.

It now comes my brainstorming request. Have you got any suggestion?

Using a shared SimpleBooleanProperty, AND-ing listeners wouldn't obviously work.

(solution) UPDATE:

Add a private final BooleanBinding binding; variable to the Controller. Then:

InputMaskChecker listener1 = new InputMaskChecker(InputMaskChecker.DATASOURCE, field1);

InputMaskChecker listener2 = new InputMaskChecker(InputMaskChecker.DATASOURCE, field2);

InputMaskChecker listener3 = new InputMaskChecker(InputMaskChecker.DATASOURCE, field3);

InputMaskChecker listener4 = new InputMaskChecker(InputMaskChecker.DATASOURCE, field4);

field1.textProperty().addListener(listener1);

field2.textProperty().addListener(listener2);

field3.textProperty().addListener(listener3);

field4.textProperty().addListener(listener4);

binding = new BooleanBinding() {

{

super.bind(listener1.erroneous, listener2.erroneous, listener3.erroneous, listener4.erroneous);

}

@Override

protected boolean computeValue() {

return (listener1.erroneous.get() || listener2.erroneous.get() || listener3.erroneous.get() || listener4.erroneous.get());

}

};

control.getDisableProperty().bind(binding);

Done ;)

网友答案:

I can suggest next approache:

Make you InputMaskChecker stateful with public SimpleBooleanProperty valid; which will be referred in update method:

@Override
public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
    valid.set(!newValue.matches(mask) || ((max_lenght > 0) ? newValue.length() > max_lenght : false) || newValue.length() == 0);
    // BTW, I would suggest to use styleclasses instead for performance reasons
    control.setStyle( valid.get() ? STYLE : "-fx-effect: null; ):
}

then you can say in "Save" button creation:

Button btn = new Button("Save");
btn.disableProperty().bind(
      listener1.valid.and(listener2.valid).and(listener3.valid).not());

or create an utility method which will add listener and update "Save" disabled property.

相关阅读:
Top