2016-06-10 8 views
3

Ich versuche, den Wert eines Textfelds nur für die Anzeige zu ändern. Dh - wenn der Benutzer versucht, eine Telefonnummer einzugeben, gibt er nur die Ziffern ein und wenn er das Feld verlässt, zeigt er formatiert an, ohne die Daten in dem Feld zu ändern.Wie formatiert man eine Zeichenfolge in einem TextField, ohne den Wert zu ändern mit JavaFX

Lassen Sie uns sagen, dass ich ein Textfeld für eine Telefonnummer haben, und es sollte nur Ziffern erlauben, maximal 10 Zeichen:

ich, dass mit einem TextFormatter umgehen kann eine UnaryOperator verwenden.

UnaryOperator<TextFormatter.Change> filter = new UnaryOperator<TextFormatter.Change>() 
      { 
       @Override 
       public TextFormatter.Change apply(TextFormatter.Change change) 
       { 
        int maxlength = 14; 
       if(change.getControlText().indexOf('(') == -1) { 
        maxlength = 10; 
       } 

       System.out.println(change); 
       if (change.getControlText().length() + change.getText().length() >= maxlength) { 
         int maxPos = maxlength - change.getControlText().length(); 
         change.setText(change.getText().substring(0, maxPos)); 
       } 


       String text = change.getText(); 
       for (int i = 0; i < text.length(); i++) 
        if (!Character.isDigit(text.charAt(i))) 
         return null; 
       return change; 
       } 
      }; 

aber ich möchte den Wert zu formatieren, wenn es lang 10 Zeichen ist (wahrscheinlich nicht formatiert, wenn = 10!):

(208) 555-1212

Wenn ich einen TextFormatter verwenden Um es zu formatieren, ändert es den Wert der Zeichenfolge zu (208) 555-1212. Wir speichern nur die Ziffern in der Datenbank 2085551212.

Ich versuchte dies mit einem StringConverter. Aber ich konnte es nicht funktionieren lassen. In der toString-Methode() entferne ich die Formatierung, aber wenn ich das tue, wird mein Textfeld nicht angezeigt.

StringConverter<String> formatter = new StringConverter<String>() 
       { 
       @Override 
       public String fromString(String string) 
       { 
        System.out.println("fromString(): before = " + string); 
        if (string.length() == 14) { 
         System.out.println("fromString(): after = " + string); 
         return string; 
        } else if (string.length() == 10 && string.indexOf('-') == -1) { 
         String result = String.format("(%s) %s-%s", string.substring(0, 3), string.substring(3, 6), 
        string.substring(6, 10)); 
         System.out.println("fromString(): after = " + result); 
         return result; 
        } else { 
         return null; 
        } 
       } 

       @Override 
       public String toString(String object) 
       { 

        System.out.println("toString(): before = " + object); 
        if(object ==null){ 
         return ""; 
        } 
        Pattern p = Pattern.compile("[\\p{Punct}\\p{Blank}]", Pattern.UNICODE_CHARACTER_CLASS); 
        Matcher m = p.matcher(object); 
        object = m.replaceAll(""); 

        System.out.println("toString(): after = " + object); 
        return object; 
       } 
       }; 

ich gebunden an ein Textfeld wie diese, die ich arbeiten würde angenommen:

txtPhone.setTextFormatter(new TextFormatter<String>(formatter, null, filter)); 
t2.textProperty().bindBidirectional(foo.fooPropertyProperty(), formatter); //I was just testing to see the results in another textfield to see if it would work. 

So bin ratlos ich. Ich möchte im Wesentlichen nur Ziffern erlauben und dann, wenn der Benutzer das Feld verlässt, den Wert in einer formatierten Weise präsentieren - ohne tatsächlich den Zeichenfolgenwert zu ändern, der zur Datenbank geht.

Antwort

3

Sie verwechseln den Zweck von toString() und fromString() Methoden miteinander in Ihrem Konverter. toString() konvertiert die Werteigenschaft Ihres Texteditors in den angezeigten Text, nicht umgekehrt. Versuchen Sie, den Code in diesen Methoden zu wechseln, und es sollte funktionieren.

Der Grund, warum Ihr Textfeld nach dem Verlieren des Fokus nichts anzeigt, ist, dass die Methode fromString() aufgerufen wird und Null zurückgibt (aus der else-Klausel). Dies schreibt null zur Werteigenschaft Ihres Editors. Die Eigenschaft "Wert ändern" aktualisiert den angezeigten Text (textProperty) durch Aufrufen von toString(null), wodurch die Texteigenschaft Ihres Editors in eine leere Zeichenfolge geändert wird.

EDIT

Unten ist mein Test-Code, ein Follow-up zur Diskussion in den Kommentaren ist. Ich habe eine große Menge Ihres ursprünglichen Codes wiederverwendet. Ich habe ein FXML-JavaFX-Projekt erstellt und TextField und Label in der FXML-Datei definiert. Die TextField akzeptiert Benutzereingaben und formatiert sie. Die Label zeigt den Wert des Textformatierers (nur Ziffern) an, der zur Datenbank gehen soll. Der Wert ist erreichbar durch Aufruf von formatter.valueProperty().get(). Ich hoffe, es hilft.

import java.net.URL; 
import java.util.ResourceBundle; 
import java.util.function.UnaryOperator; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 
import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.scene.control.Label; 
import javafx.scene.control.TextField; 
import javafx.scene.control.TextFormatter; 
import javafx.util.StringConverter; 

public class FXMLDocumentController implements Initializable { 

// label displays phone number containing only digits (for database) 
@FXML private Label label; 

/* field displays formatted text (XXX)-XXX-XXXX after user types 
10 digits and presses Enter or if the field looses focus */ 
@FXML private TextField field; 

@Override 
public void initialize(URL url, ResourceBundle rb) { 

    UnaryOperator<TextFormatter.Change> filter = new UnaryOperator<TextFormatter.Change>() { 
     @Override 
     public TextFormatter.Change apply(TextFormatter.Change change) { 
      if (!change.isContentChange()) { 
       /* nothing is added or deleted but change must be returned 
       * as it contains selection info and caret position 
       */ 
       return change; 
      } 

      int maxlength = 14; 
      if (change.getControlText().indexOf('(') == -1) { 
       maxlength = 10; 
      } 

      if (change.getControlNewText().length() > maxlength 
        || change.getText().matches("\\D+")) { 
       // invalid input. Cancel the change 
       return null; 
      } 
      return change; 
     } 
    }; 

    StringConverter<String> converter = new StringConverter<String>() { 

     // updates displayed text from commited value 
     @Override 
     public String toString(String commitedText) { 
      if (commitedText == null) { 
       // don't change displayed text 
       return field.getText(); 
      } 

      if (commitedText.length() == 10 && !commitedText.matches("\\D+")) { 
       return String.format("(%s) %s-%s", commitedText.substring(0, 3), commitedText.substring(3, 6), 
            commitedText.substring(6, 10)); 
      } else { 
       /* Commited text can be either null or 10 digits. 
       * Nothing else is allowed by fromString() method unless changed directly 
       */ 
       throw new IllegalStateException(
         "Unexpected or incomplete phone number value: " + commitedText); 
      } 
     } 

     // commits displayed text to value 
     @Override 
     public String fromString(String displayedText) { 
      // remove formatting characters 
      Pattern p = Pattern.compile("[\\p{Punct}\\p{Blank}]", Pattern.UNICODE_CHARACTER_CLASS); 
      Matcher m = p.matcher(displayedText); 
      displayedText = m.replaceAll(""); 

      if (displayedText.length() != 10) { 
       // user is not done typing the number. Don't commit 
       return null; 
      } 

      return displayedText; 
     } 
    }; 
    TextFormatter<String> formatter = new TextFormatter<String>(converter, "1234567890", filter); 
    field.setTextFormatter(formatter); 
    label.textProperty().bind(formatter.valueProperty()); 
} 
} 
+0

Ich versuchte beide Möglichkeiten, aber es funktioniert immer noch nicht. Vielen Dank. –

+0

Ich habe es gerade selbst getestet und es funktioniert. Wenn Sie den Wert an die Datenbank übergeben, müssen Sie die Werteigenschaft des Formatierungsprogramms lesen.Erstellen Sie zunächst einen Verweis auf Ihr Formatierungsobjekt, bevor Sie es auf das 'TextField' setzen:' TextFormatter Formatierer = neuer TextFormatter (Formatierer, "1234567890", Filter); '. Dann kann Ihre Datenbank Nur-Ziffern-Text über 'formatter.valueProperty(). Get()' lesen. – Mosalx

+0

Dies verursacht immer noch Probleme. Beim ersten Mal funktioniert es, beim zweiten Mal zeigt es den formatierten Wert an. Ich könnte es einfach aufgeben, dafür Textformatierer zu verwenden und andere Mittel zu verwenden. Es ist schade, dass das nicht auf einfache und einfache Weise funktioniert. –