これまでのTextField検証の実装を改善しました。今回は、バインドを使用してリアルタイム検証を使用してカスタムコントロールを作成します。これは、より多くのJavaコードを必要とせずにFXMLで使用できます。JavaFX 2.2 FXML Validated TextField
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;
import javafx.scene.effect.BlurType;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
import javafx.scene.paint.Color;
/**
* <p>
* TextField with regex-based real-time input validation.
* JavaFX 2 and FXML compatible. </p>
* <p>
* FXML code example:<div>
* {@code <ValidatedTextField fx:id="validatedTextField" minLength="1" maxLength="1" mask="^[0-9]*$" />}
* </div>
* </p>
*
* @author 82300009
*/
public final class ValidatedTextField extends TextField {
private final BooleanProperty invalid = new SimpleBooleanProperty(false);
private final StringProperty mask;
private final IntegerProperty minLength;
private final IntegerProperty maxLength;
private Effect invalidEffect = new DropShadow(BlurType.GAUSSIAN, Color.RED, 4, 0.0, 0, 0);
public ValidatedTextField() {
super();
this.mask = new SimpleStringProperty(".");
this.minLength = new SimpleIntegerProperty(-1);
this.maxLength = new SimpleIntegerProperty(-1);
bind();
}
public ValidatedTextField(String mask, int minLength, int maxLength, boolean nullable) {
this(mask, minLength, maxLength, nullable, null);
}
public ValidatedTextField(String mask, int minLength, int maxLength, boolean nullable, String string) {
super(string);
this.mask = new SimpleStringProperty(mask);
this.minLength = new SimpleIntegerProperty(minLength);
this.maxLength = new SimpleIntegerProperty(maxLength);
bind();
}
public ReadOnlyBooleanProperty invalidProperty() {
return invalid;
}
public ReadOnlyStringProperty maskProperty() {
return mask;
}
public ReadOnlyIntegerProperty minLengthProperty() {
return minLength;
}
public ReadOnlyIntegerProperty maxLengthProperty() {
return maxLength;
}
public boolean getInvalid() {
return invalid.get();
}
public String getMask() {
return mask.get();
}
public void setMask(String mask) {
this.mask.set(mask);
}
public int getMinLength() {
return minLength.get();
}
public void setMinLength(int minLength) {
this.minLength.set(minLength);
}
public int getMaxLength() {
return maxLength.get();
}
public void setMaxLength(int maxLength) {
this.maxLength.set(maxLength);
}
public Effect getInvalidEffect() {
return this.invalidEffect;
}
public void setInvalidEffect(Effect effect) {
this.invalidEffect = effect;
}
private void bind() {
this.invalid.bind(maskCheck().or(minLengthCheck()));
this.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> ov, String t, String t1) {
if (textProperty().get().length() > maxLength.get()) {
setText(t);
}
}
});
this.invalid.addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
if (t^t1) {
if (t1) {
// setStyle("-fx-font-weight: bold; -fx-text-fill: red;");
setEffect(invalidEffect);
} else {
// setStyle("-fx-font-weight: normal; -fx-text-fill: inherit;");
setEffect(null);
}
}
}
});
}
private BooleanBinding maskCheck() {
return new BooleanBinding() {
{
super.bind(textProperty(), mask);
}
@Override
protected boolean computeValue() {
return !textProperty().get().matches(mask.get());
}
};
}
private BooleanBinding minLengthCheck() {
return new BooleanBinding() {
{
super.bind(textProperty(), minLength);
}
@Override
protected boolean computeValue() {
return textProperty().get().length() < minLength.get();
}
};
}
private BooleanBinding maxLengthCheck() {
return new BooleanBinding() {
{
super.bind(textProperty(), maxLength);
}
@Override
protected boolean computeValue() {
return textProperty().get().length() > maxLength.get();
}
};
}
}
しかし、「無効な」グラフィック効果についての些細な点はまだあります。 あなたがここに見ることができるように:
this.invalid.addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
if (t^t1) {
if (t1) {
// setStyle("-fx-font-weight: bold; -fx-text-fill: red;");
setEffect(invalidEffect);
} else {
// setStyle("-fx-font-weight: normal; -fx-text-fill: inherit;");
setEffect(null);
}
}
}
});
は私がでsetStyleが、-fx-フォントの太さを使用してみました:継承します。はコードを破壊します(なぜなら、デフォルト値である必要がないからです)。 StyleClassをインジェクトすると、invalidがfalseのときに元に戻せないため、動作しません。
ヒント?内側の聴取者を切り離して、他のエフェクトを使用して別の外部を添付することももちろん可能です(f.i. TextFieldエフェクトを変更する代わりに緑色の目盛り記号が表示されます)。
あなたは:)
、すなわちむしろ遅いようです...さらに、擬似状態は適用されません。無効です。 無効な変数値を読み込んで疑似ステートを適用するべきではありませんか? – matticala
私は、スタイルの追加/削除手法を使用していて、それが遅いとは見当たりませんでした。このコード部分が本当に問題であるかどうかを測定する必要があります。あなたは、提供された状態以外の状態を持つようにスキンを実装する必要があります。いくつかのコード例については、https://github.com/shemnon/DeckControl/tree/master/src/main/java/com/github/shemnon/deckcontrol/skinを参照してください。 –
私はそう推測しました。実際には、適切な再配布可能なコントロールを実装するためのJavaOne 2011のチュートリアル(http://www.parleys.com/#st=5&id=2789&sl=35)を見ています。私もそのギターを見ていきます、ありがとう! – matticala