2017-07-19 136 views
3

我想創建JavaFX中可編輯的TableView,顯示存儲在一個自定義類InventoryLocation各種值。其中一些值是字符串,而另一些則是各種數字數據類型(short,int,double),並且一些字符串具有與它們相關聯的特定所需格式。我使用類似下面的代碼塊來定義每個表列,使用SortStringConverter()或類似採取文字輸入,並將其轉換爲目標數據類型:可編輯的TableView JavaFX中,只有數字輸入

TableColumn<InventoryLocation,Short> CabinetColumn = new TableColumn<>("Cabinet"); 
    CabinetColumn.setMinWidth(50); 
    CabinetColumn.setCellValueFactory(new PropertyValueFactory<>("Cabinet")); 
    CabinetColumn.setCellFactory(TextFieldTableCell.forTableColumn(new ShortStringConverter())); 

不過,我想阻止用戶輸入任何無效的數據開始。對於上面的例子,他們不應該能夠輸入任何非數字字符。在其他地方我的應用程序,在簡單的TextField,我使用這樣的事情來執行正則表達式匹配用戶輸入:

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

如何申請類似於可編輯的TableView用於文本輸入的東西嗎?目前,第一個代碼塊將允許用戶編寫他們喜歡的任何值,並且如果該字符串不能被轉換爲short,則會拋出數字格式異常。我希望代碼能夠防止他們首先輸入無效值。

+0

請參閱此相關的問題:什麼是推薦的方式,使在JavaFX的數字文本字段?](https://開頭stackoverflow.com/questions/7555564/what-is-the-recommended-way-to-make-a-numeric-textfield-in-javafx)。注意這是在Java中加入引用該答案[的TextFormatter](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TextFormatter.html),8。 – jewelsea

+1

解決方案可能會是將TextFormatter應用於由TextFieldTableCell創建的TextField。不幸的是,這些文本框是私有的那類,所以也許嘗試複製和粘貼TextFieldTableCell的代碼來創建一個新的類FormattedTextFieldTableCell,使您可以設置所生成的文本字段適當的文本格式化。 – jewelsea

回答

3

你需要創建一個自定義的TableCell - 例如:

public class EditableBigDecimalTableCell<T> extends TableCell<T, BigDecimal> { 
private TextField textField; 
private int minDecimals, maxDecimals; 
/** 
* This is the default - we will use this as 2 decimal places 
*/ 
public EditableBigDecimalTableCell() { 
    minDecimals = 2; 
    maxDecimals = 2; 
} 

/** 
* Used when the cell needs to have a different behavior than 2 decimals 
*/ 
public EditableBigDecimalTableCell (int min, int max) { 
    minDecimals = min; 
    maxDecimals = max; 
} 

@Override 
public void startEdit() { 
    if(editableProperty().get()){ 
     if (!isEmpty()) { 
      super.startEdit(); 
      createTextField(); 
      setText(null); 
      setGraphic(textField); 
      textField.requestFocus(); 
     } 
    } 
} 

@Override 
public void cancelEdit() { 
    super.cancelEdit(); 
    setText(getItem() != null ? getItem().toPlainString() : null); 
    setGraphic(null); 
} 

@Override 
public void updateItem(BigDecimal item, boolean empty) { 
    super.updateItem(item, empty); 
    if (empty) { 
     setText(null); 
     setGraphic(null); 
    } else { 
     if (isEditing()) { 
      if (textField != null) { 
       textField.setText(getString()); 
       textField.selectAll(); 
      } 
      setText(null); 
      setGraphic(textField); 
     } else { 
      setText(getString()); 
      setGraphic(null); 
     } 
    } 
} 

private void createTextField() { 
    textField = new TextField(); 
    textField.setTextFormatter(new DecimalTextFormatter(minDecimals, maxDecimals)); 
    textField.setText(getString()); 

    textField.setOnAction(evt -> { 
     if(textField.getText() != null && !textField.getText().isEmpty()){ 
      NumberStringConverter nsc = new NumberStringConverter(); 
      Number n = nsc.fromString(textField.getText()); 
      commitEdit(BigDecimal.valueOf(n.doubleValue())); 
     } 
    }); 
    textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2); 

    textField.setOnKeyPressed((ke) -> { 
     if (ke.getCode().equals(KeyCode.ESCAPE)) { 
      cancelEdit(); 
     } 
    }); 

    textField.setAlignment(Pos.CENTER_RIGHT); 
    this.setAlignment(Pos.CENTER_RIGHT); 
} 

private String getString() { 
    NumberFormat nf = NumberFormat.getNumberInstance(); 
    nf.setMinimumFractionDigits(minDecimals); 
    nf.setMaximumFractionDigits(maxDecimals); 
    return getItem() == null ? "" : nf.format(getItem()); 
} 

@Override 
public void commitEdit(BigDecimal item) { 
    if (isEditing()) { 
     super.commitEdit(item); 
    } else { 
     final TableView<T> table = getTableView(); 
     if (table != null) { 
      TablePosition<T, BigDecimal> position = new TablePosition<T, BigDecimal>(getTableView(), 
        getTableRow().getIndex(), getTableColumn()); 
      CellEditEvent<T, BigDecimal> editEvent = new CellEditEvent<T, BigDecimal>(table, position, 
        TableColumn.editCommitEvent(), item); 
      Event.fireEvent(getTableColumn(), editEvent); 
     } 
     updateItem(item, false); 
     if (table != null) { 
      table.edit(-1, null); 
     } 

    } 
} 

} 

使用格式化,這將阻止你不想要的值。

public class DecimalTextFormatter extends TextFormatter<Number> { 
private static DecimalFormat format = new DecimalFormat("#.0;-#.0"); 
public DecimalTextFormatter(int minDecimals, int maxDecimals) { 
    super(
     new StringConverter<Number>() { 
      @Override 
      public String toString(Number object) { 
       if(object == null){ 
        return ""; 
       } 
       String format = "0."; 
       for (int i = 0; i < maxDecimals; i++) { 
        if(i < minDecimals) { 
         format = format + "0" ; 
        }else { 
         format = format + "#" ; 
        } 
       } 
       format = format + ";-" + format; 
       DecimalFormat df = new DecimalFormat(format); 
       String formatted = df.format(object); 
       return formatted; 
      } 

      @Override 
      public Number fromString(String string){ 
       try { 
        return format.parse(string); 
       } catch (ParseException e) { 
        return null; 
       } 
      } 
     }, 
     0, 
     new UnaryOperator<TextFormatter.Change>() { 
      @Override 
      public TextFormatter.Change apply(TextFormatter.Change change) { 
       if (change.getControlNewText().isEmpty()) 
       { 
        return change; 
       } 

       ParsePosition parsePosition = new ParsePosition(0); 
       Object object = format.parse(change.getControlNewText(), parsePosition); 

       if(change.getControlNewText().equals("-")){ 
        return change; 
       } 

       if(change.getCaretPosition() == 1){ 
        if(change.getControlNewText().equals(".")){ 
         return change; 
        } 
       } 

       if (object == null || parsePosition.getIndex() < change.getControlNewText().length()) 
       { 
        return null; 
       } 
       else 
       { 
        int decPos = change.getControlNewText().indexOf("."); 
        if(decPos > 0){ 
         int numberOfDecimals = change.getControlNewText().substring(decPos+1).length(); 
         if(numberOfDecimals > maxDecimals){ 
          return null; 
         } 
        } 
        return change; 
       } 
      } 
     } 
    ); 
} 

}

然後使用您的列:

numberColumn.setCellFactory(col -> new EditableBigDecimalTableCell<MyDTO>());