2012-09-26 2 views
0

JavaFX 2 TableView에서 데이터의 Null 값을 처리하는 데 심각한 문제가 있습니다. 실제로 많은 문제가 있습니다. 아래에 표시된 문제에 대한 간단한 데모를 작성했습니다.셀의 null 값 처리

본질적으로 문제는 일부 데이터가 null 일 수 있으며 빈 문자열과 같은 값으로 null을 강요하는 것은 유효하지 않으며 null이어야합니다. 실제 코드에서 저는 null 값을 가지고 있습니다. 예제를 단순하게 유지하려면 아래에 null 문자열을 보여 줬습니다.

테이블의 행 1과 테이블 2에는 널값이 있습니다. 두 개의 열은 서로 다르며 첫 번째 행은 편집 가능한 셀의 두 번째 구현 인 TextFieldTableCell의 동작을 보여줍니다. 둘 다 같은 잘못된 동작을 보여줍니다.

현재의 행동이 이것이다 :

  1. 눌러 편집을 커밋 입력 셀에 값을 입력 편집 모드
  2. 를 입력 할 셀을 클릭
  3. 아무것도
을 발생하지

4 단계에서 열의 onEditCommit 처리기가 호출 될 것으로 예상되지만 그렇지 않습니다. (가) 때문에 것은, commitEdit의 첫 번째 줄의 발생하지 커밋 javax.scene.control.TableCell의 소스를 살펴 갖는 것입니다 :

if (! isEditing()) return; 

세포이기 때문에 널 편집 속성이 설정 결코 극복 보인다 나는 아직까지 모든 코드를 추적하지 못했지만 왜 그것이 사실로 바뀌지 않는지를 알기는하지만 인정합니다.

언제나 도움을 주셔서 감사합니다.


기본 응용 프로그램

package example; 

import javafx.application.Application; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.event.EventHandler; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.control.cell.TextFieldTableCell; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

public class NullCellEditingExample extends Application { 

    private TableView table = new TableView(); 
    private final ObservableList<Person> data = 
      FXCollections.observableArrayList(new Person(null, "Smith"), new Person("Isabella", null), 
      new Person("Ethan", "Williams"), new Person("Emma", "Jones"), new Person("Michael", "Brown")); 

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

    @Override 
    public void start(Stage stage) { 
     Scene scene = new Scene(new Group()); 

     TableColumn firstNameCol = createSimpleFirstNameColumn(); 
     TableColumn lastNameCol = createLastNameColumn(); 
     table.setItems(data); 
     table.getColumns().addAll(firstNameCol, lastNameCol); 
     table.setEditable(true); 

     ((Group) scene.getRoot()).getChildren().addAll(table); 
     stage.setScene(scene); 
     stage.show(); 
    } 

    private TableColumn createSimpleFirstNameColumn() { 
     TableColumn firstNameCol = new TableColumn("First Name"); 
     firstNameCol.setMinWidth(100); 
     firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName")); 
     firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn()); 
     firstNameCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Person, String>>() { 
      @Override 
      public void handle(TableColumn.CellEditEvent<Person, String> t) { 
       ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setFirstName(t.getNewValue()); 
      } 
     }); 

     return firstNameCol; 
    } 

    private TableColumn createLastNameColumn() { 
     Callback<TableColumn, TableCell> editableFactory = new Callback<TableColumn, TableCell>() { 
      @Override 
      public TableCell call(TableColumn p) { 
       return new EditingCell(); 
      } 
     }; 

     TableColumn lastNameCol = new TableColumn("Last Name"); 
     lastNameCol.setMinWidth(100); 
     lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName")); 
     lastNameCol.setCellFactory(editableFactory); 
     lastNameCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Person, String>>() { 
      @Override 
      public void handle(TableColumn.CellEditEvent<Person, String> t) { 
       t.getRowValue().setLastName(t.getNewValue()); 
      } 
     }); 

     return lastNameCol; 
    } 
} 

편집 셀

package example; 

import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.event.EventHandler; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TextField; 
import javafx.scene.input.KeyCode; 
import javafx.scene.input.KeyEvent; 

public class EditingCell extends TableCell<Person, String> { 

    private TextField textField; 

    public EditingCell() { 
    } 

    @Override 
    public void startEdit() { 
     super.startEdit(); 
     if(textField == null) { 
      createTextField(); 
     } 
     setText(null); 
     setGraphic(textField); 
     textField.selectAll(); 
    } 

    @Override 
    public void cancelEdit() { 
     super.cancelEdit(); 
     setText((String) getItem()); 
     setGraphic(null); 
    } 

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

    private void createTextField() { 
     textField = new TextField(getString()); 
     textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2); 
     textField.focusedProperty().addListener(new ChangeListener<Boolean>() { 
      @Override 
      public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) { 
       if (!arg2) { commitEdit(textField.getText()); } 
      } 
     }); 

     textField.setOnKeyReleased(new EventHandler<KeyEvent>() { 
      @Override 
      public void handle(KeyEvent t) { 
       if (t.getCode() == KeyCode.ENTER) { 
        String value = textField.getText(); 
        if (value != null) { commitEdit(value); } else { commitEdit(null); } 
       } else if (t.getCode() == KeyCode.ESCAPE) { 
        cancelEdit(); 
       } 
      } 
     }); 
    } 

    private String getString() { 
     return getItem() == null ? "" : getItem().toString(); 
    } 
} 

사람

package example; 

import javafx.beans.property.SimpleStringProperty; 

public class Person { 

    private final SimpleStringProperty firstName; 
    private final SimpleStringProperty lastName; 

    public Person(String firstName, String lastName) { 
     this.firstName = new SimpleStringProperty(firstName); 
     this.lastName = new SimpleStringProperty(lastName); 
    } 

    public String getFirstName() { 
     return firstName.get(); 
    } 

    public void setFirstName(String firstName) { 
     this.firstName.set(firstName); 
    } 

    public SimpleStringProperty firstNameProperty() { 
     return firstName; 
    } 

    public String getLastName() { 
     return lastName.get(); 
    } 

    public void setLastName(String lastName) { 
     this.lastName.set(lastName); 
    } 

    public SimpleStringProperty lastNameProperty() { 
     return lastName; 
    } 
} 

답변

2

게시 이후 나는 기본적으로 동일한 another question을 발견했습니다. 그들은 항상 문자열 (예 : 빈 문자열 사용)에 대해서는 괜찮지 만 날짜 나 다른 데이터 유형에는 허용되지 않는 "빈"값이없는 null 값을 피하는 방식을 취했습니다.

해결책은 EditingCell.updateItem 메소드의 super.updateItem 호출에 false 값을 전달하는 것입니다. 누구든지 완전한 분석에 관심이 있다면 full write up을 작성했습니다.