2012-11-16 14 views
5

Poprawiłem moją poprzednią implementację sprawdzania poprawności TextField, tym razem czyniąc prawdziwą kontrolę niestandardową z weryfikacją w czasie rzeczywistym za pomocą wiązania. Można go używać z FXML bez potrzeby używania więcej kodu Java.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(); 
      } 
     }; 
    } 
} 

Nadal istnieje jednak drobna kwestia dotycząca "nieważnego" efektu graficznego. Jak widać tutaj:

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); 
        } 
       } 

      } 
     }); 

Próbowałem z setStyle lecz stosując -fx-font-weight: odziedziczyć; łamie kod (nie dlaczego, ponieważ powinien być jego domyślną wartością). Wstrzykiwanie klasy StyleClass nie działa, ponieważ nie mogę go przywrócić, gdy nieprawidłowy jest fałszywy.

Jakaś wskazówka? Oczywiście można odłączyć wewnętrznego słuchacza i dołączyć go na zewnątrz z innymi efektami (np. Pokazując zielony znak, zamiast zmieniać efekt TextField).

Jesteś wolny, aby korzystać z kodu, jeśli przeszkadza :)

Odpowiedz

3

zawsze można przywrócić styl poprzez usunięcie go z listy klas stylów tj

node.getStyleClass().remove("my-style"); 
+0

mam teraz, ale to za pomocą wydaje się raczej powolny ... ponadto nie stosuje pseudo-stanu: nieprawidłowy. Czy nie powinien odczytać niepoprawną wartość zmiennej i zastosować pseudostate? – matticala

+1

Użyłem techniki dodawania/usuwania stylu i nie znalazłem jej zbyt wolno, możesz potrzebować zmierzyć, czy ta część kodu jest naprawdę problemem. Musisz zaimplementować Skórę, aby mieć stan inny niż podany. Zobacz https://github.com/shemnon/DeckControl/tree/master/src/main/java/com/github/shemnon/deckcontrol/skin dla niektórych przykładów kodu. –

+0

Zgadłem. W rzeczywistości teraz oglądam samouczek JavaOne 2011 na temat tworzenia niestandardowych formantów (http://www.parleys.com/#st=5&id=2789&sl=35) w celu wdrożenia właściwej kontroli redystrybucyjnej. Przyjrzę się również temu githubowi, wielkie dzięki! – matticala

Powiązane problemy