2016-11-07 11 views
7

Próbuję utworzyć TextField liczbową liczb całkowitych za pomocą TextFormatter JavaFX 8.TextField numeryczny dla liczb całkowitych JavaFX 8 z TextFormatter i/lub UnaryOperator

rozwiązanie z UnaryOperator:

UnaryOperator<Change> integerFilter = change -> { 
    String input = change.getText(); 
    if (input.matches("[0-9]*")) { 
     return change; 
    } 
    return null; 
}; 

myNumericField.setTextFormatter(new TextFormatter<String>(integerFilter)); 

Rozwiązanie z IntegerStringConverter:

myNumericField.setTextFormatter(new TextFormatter<>(new IntegerStringConverter())); 

Oba rozwiązania mają swoje własne problemy. Za pomocą UnaryOperatora mogę wprowadzać cyfry od 0 do 9, jak zamierzano, ale muszę też wprowadzić wartości ujemne, takie jak "-512", gdzie znak jest dozwolony tylko na pierwszej pozycji. Nie chcę również numerów takich jak "00016", które są nadal możliwe.

Metoda IntegerStringConverter działa lepiej: każdy nieprawidłowy numer jak "-16-123" nie jest akceptowany, a liczby takie jak "0123" są konwertowane na "123". Ale konwersja ma miejsce tylko wtedy, gdy tekst jest zatwierdzony (przez naciśnięcie klawisza Enter) lub gdy TextField traci ostrość.

Czy istnieje sposób na wymuszenie konwersji drugiej metody za pomocą IntegerStringConverter za każdym razem, gdy wartość pola TextField jest aktualizowana?

Odpowiedz

13

Konwerter różni się od filtra: konwerter określa, w jaki sposób przekonwertować tekst na wartość, a filtry filtrów mogą zmienić użytkownika. Wygląda na to, że chcesz oba, ale chcesz, aby filtr dokładniej filtrował dozwolone zmiany.

Zazwyczaj najłatwiej jest sprawdzić nową wartość tekstu, jeśli zmiana została zaakceptowana. Chcesz opcjonalnie mieć -, a następnie 1-9 z dowolną liczbą cyfr po nim. Ważne jest, aby zezwolić na pusty ciąg, w przeciwnym razie użytkownik nie będzie mógł usunąć wszystkiego.

więc prawdopodobnie trzeba coś takiego

UnaryOperator<Change> integerFilter = change -> { 
    String newText = change.getControlNewText(); 
    if (newText.matches("-?([1-9][0-9]*)?")) { 
     return change; 
    } 
    return null; 
}; 

myNumericField.setTextFormatter(
    new TextFormatter<Integer>(new IntegerStringConverter(), 0, integerFilter)); 

Można nawet dodać więcej funkcjonalności do filtra aby przetwarzać - w sprytniejszy sposób, na przykład

UnaryOperator<Change> integerFilter = change -> { 
    String newText = change.getControlNewText(); 
    // if proposed change results in a valid value, return change as-is: 
    if (newText.matches("-?([1-9][0-9]*)?")) { 
     return change; 
    } else if ("-".equals(change.getText())) { 

     // if user types or pastes a "-" in middle of current text, 
     // toggle sign of value: 

     if (change.getControlText().startsWith("-")) { 
      // if we currently start with a "-", remove first character: 
      change.setText(""); 
      change.setRange(0, 1); 
      // since we're deleting a character instead of adding one, 
      // the caret position needs to move back one, instead of 
      // moving forward one, so we modify the proposed change to 
      // move the caret two places earlier than the proposed change: 
      change.setCaretPosition(change.getCaretPosition()-2); 
      change.setAnchor(change.getAnchor()-2); 
     } else { 
      // otherwise just insert at the beginning of the text: 
      change.setRange(0, 0); 
     } 
     return change ; 
    } 
    // invalid change, veto it by returning null: 
    return null; 
}; 

To pozwoli prasę użytkownika - w dowolnym momencie i będzie przełączać znak całkowitej.

SSCCE:

import java.util.function.UnaryOperator; 

import javafx.application.Application; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.TextField; 
import javafx.scene.control.TextFormatter; 
import javafx.scene.control.TextFormatter.Change; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 
import javafx.util.StringConverter; 
import javafx.util.converter.IntegerStringConverter; 

public class IntegerFieldExample extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     TextField integerField = new TextField(); 
     UnaryOperator<Change> integerFilter = change -> { 
      String newText = change.getControlNewText(); 
      if (newText.matches("-?([1-9][0-9]*)?")) { 
       return change; 
      } else if ("-".equals(change.getText())) { 
       if (change.getControlText().startsWith("-")) { 
        change.setText(""); 
        change.setRange(0, 1); 
        change.setCaretPosition(change.getCaretPosition()-2); 
        change.setAnchor(change.getAnchor()-2); 
        return change ; 
       } else { 
        change.setRange(0, 0); 
        return change ; 
       } 
      } 
      return null; 
     }; 

     // modified version of standard converter that evaluates an empty string 
     // as zero instead of null: 
     StringConverter<Integer> converter = new IntegerStringConverter() { 
      @Override 
      public Integer fromString(String s) { 
       if (s.isEmpty()) return 0 ; 
       return super.fromString(s); 
      } 
     }; 

     TextFormatter<Integer> textFormatter = 
       new TextFormatter<Integer>(converter, 0, integerFilter); 
     integerField.setTextFormatter(textFormatter); 

     // demo listener: 
     textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> System.out.println(newValue)); 

     VBox root = new VBox(5, integerField, new Button("Click Me")); 
     root.setAlignment(Pos.CENTER); 
     Scene scene = new Scene(root, 300, 120); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+1

Inteligentne zastosowanie '' na grupie numer?! Myślałem o '-? ([1-9]? | [1-9] [0-9] *)', ale jest to o wiele czystsze! – flakes

+1

Naprawdę doceniam Twój wysiłek, Twoje rozwiązanie działa idealnie! – ShadowEagle

1
TextField txtpoint = new TextField(); 
    txtpoint.textProperty().addListener(new ChangeListener<String>() { 
     @Override 
     public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { 
      if (!newValue.isEmpty()) { 
       try { 
        long pointI = Integer.parseInt(newValue); 
        txtpoint.setText(String.valueOf(pointI)); 
       } catch (Exception e) { 
        txtpoint.clear(); 
        txtpoint.setText(getNumber(oldValue)); 
       } 
      } 
     } 
    }); 


private String getNumber(String value) { 
    String n = ""; 
    try { 
     return String.valueOf(Integer.parseInt(value)); 
    } catch (Exception e) { 
     String[] array = value.split(""); 
     for (String tab : array) { 
      try { 
       System.out.println(tab); 
       n = n.concat(String.valueOf(Integer.parseInt(String.valueOf(tab)))); 
      } catch (Exception ex) { 
       System.out.println("not nomber"); 
      } 
     } 
     return n; 
    } 
} 
+1

W przypadku przepełnienia stosu niektóre słowa instrukcji wyjaśnienia/użytkowania są zazwyczaj mile widziane. – mkl

Powiązane problemy