2016-12-26 8 views
1

초기화시 ChangeListener 내부에서 변경 방법을 실행할 수 있습니까? 변경 사항이 발생할 때만 실행되기 때문입니다. 예를 들어 내가이 비어 때 0 값의 설정하려는 TextField를 가지고 있고, 나는 이런 식으로 작업을 수행합니다 JavaFX : Run ChangeListener

textField.textProperty().addListener(new ChangeListener<String>() { 
     @Override 
     public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { 
      if (!newValue.matches("\\d*")) { 
       textField.setText(newValue.replaceAll("[^\\d]", "")); 
      } 

      if (newValue.isEmpty()) 
       textField.setText("0"); 

     } 
    }); 

그러나 변경된 메소드가 호출되지 않는 응용 프로그램의 시작

. 그렇다면이 문제를 해결하는 방법은 무엇입니까?

+0

응용 프로그램을 시작할 때 어떤 텍스트가 있습니까? –

+0

비었지만 TextField는 많은 경우 중 하나입니다. 또 다른 경우는 TableView에서 선택한 항목에 따라 속성을 비활성화하려는 Button입니다. –

+0

하지만 비어있는 경우 리스너는이를 ""0 "'으로 변경합니다. 그럼 왜 그것을 "0"'으로 초기화하지 않겠습니까? 다른 컨트롤과 마찬가지로 : 상태를 사용자의 요구 사항과 일치하도록 초기화하십시오. ('Button'을 사용하면'button.disableProperty(). bind (tableView.getSelectionModel(). selectedItemProperty(). isNull());') 대신 바인딩을 사용할 수 있습니다. –

답변

2

속성에 추가 된 수신기에 액세스 할 수있는 방법이 없습니다.

ChangeListener<String> textFieldListener = (observable, oldValue, newValue) -> { 

    if (!newValue.matches("\\d*")) { 
     textField.setText(newValue.replaceAll("[^\\d]", "")); 
    } 

    if (newValue.isEmpty()) 
     textField.setText("0"); 

}; 

textField.textProperty().addListener(textFieldListener); 
textFieldListener.changed(null, null, textField.getText()); 

또는 아마도 더 자연스럽게, 단지 다른 방법으로 실제 기능을 이동 : 분명히 당신은 단지에 대한 참조를 유지할 수

textField.textProperty().addListener((observable, oldValue, newValue) -> vetoTextFieldChanges()); 
vetoTextFieldChanges(); 

// ... 

private void vetoTextFieldChanges() { 
    String newText = textField.getText(); 
    if (!newText.matches("\\d*")) { 
     textField.setText(newText.replaceAll("[^\\d]", "")); 
    } 

    if (newText.isEmpty()) 
     textField.setText("0"); 
} 

주 그 변화를보고 전체 접근 방법과 그런 다음 비즈니스 논리와 일치하지 않는 경우 수정하면 만족스럽지 않습니다. 예를 들어, 속성에 등록 된 다른 리스너가있는 경우 텍스트의 중간 (잘못된) 값이 표시 될 수 있습니다. 이를 수행하는 방법은 TextFormatter을 사용하는 것입니다. TextFormatter은 모두 이 업데이트되기 전에 텍스트에 요청 된 변경을 거부하고 텍스트를 적절한 값으로 변환하도록 허용합니다. 따라서 귀하의 경우에 당신은 할 수 :

UnaryOperator<TextFormatter.Change> filter = change -> { 

    // remove any non-digit characters from inserted text: 
    if (! change.getText().matches("\\d*")) { 
     change.setText(change.getText().replaceAll("[^\\d]", "")); 
    } 

    // if new text is empty, replace all text with "0": 
    if (change.getControlNewText().isEmpty()) { 
     change.setRange(0, change.getControlText().length()); 
     change.setText("0"); 
    } 

    return change ; 
}; 

TextFormatter<Integer> formatter = new TextFormatter<Integer>(new IntegerStringConverter(), 0, filter); 
textField.setTextFormatter(formatter); 

이제 직접 포맷터의 value 특성을 통해 (숫자) 값을 얻을 수있는 포맷을 사용, 등 모델에 바인드 할 수 있습니다

// assume model is a data model and valueProperty() returns a Property<Integer>: 
formatter.valueProperty().bindBidirectional(model.valueProperty()); 

이 바인딩은 모델이 변경 될 때 포맷터 (결과적으로 텍스트 필드)를 업데이트하고 모델 값에 따라 초기화하여 원래의 질문에 대한 해결책을 제공한다는 점에 유의하십시오.