2015-11-18 40 views
1

請看下面的例子:複選框內的TableCell打破了遍歷順序

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.scene.control.CheckBox; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.HBox; 
import javafx.stage.Stage; 

public class TestCheckBoxTab extends Application { 
    public void start (Stage stage) { 
     HBox root = new HBox(); 
     root.getChildren().addAll(new TextField(), new TextField(), new CheckBox(), new TextField()); 

     stage.setScene(new Scene(root)); 
     stage.show(); 
    } 

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

在這裏,您可以輕鬆地使用Tab鍵和Shift + Tab命令通過不同的控制來遍歷,它工作正常。

但是,如果您在TableView中的表單元格內具有相同的控件,則CheckBox會中斷遍歷順序。這表現在下面的例子:

import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.scene.Scene; 
import javafx.scene.control.CheckBox; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.TextField; 
import javafx.stage.Stage; 

public class AlwaysEditableTable extends Application { 
    public void start(Stage stage) { 

     TableView<ObservableList<StringProperty>> table = new TableView<>(); 
     table.setEditable(true); 
     table.getSelectionModel().setCellSelectionEnabled(true); 
     table.setPrefWidth(505); 

     // Dummy columns 
     ObservableList<String> columns = FXCollections.observableArrayList("Column1", "Column2", "Column3", "Column4", 
       "Column5"); 

     // Dummy data 
     ObservableList<StringProperty> row1 = FXCollections.observableArrayList(new SimpleStringProperty("Cell1"), 
       new SimpleStringProperty("Cell2"), new SimpleStringProperty("0"), new SimpleStringProperty("Cell4"), 
       new SimpleStringProperty("1")); 
     ObservableList<ObservableList<StringProperty>> data = FXCollections.observableArrayList(); 
     data.add(row1); 

     for (int i = 0; i < columns.size(); i++) { 
      final int j = i; 
      TableColumn<ObservableList<StringProperty>, String> col = new TableColumn<>(columns.get(i)); 
      col.setCellValueFactory(param -> param.getValue().get(j)); 
      col.setPrefWidth(100); 

      if (i == 2 || i == 4) { 
       col.setCellFactory(e -> new CheckBoxCell(j)); 
      } else { 
       col.setCellFactory(e -> new AlwaysEditingCell(j)); 
      } 

      table.getColumns().add(col); 
     } 

     table.setItems(data); 

     Scene scene = new Scene(table); 
     stage.setScene(scene); 
     stage.show(); 
    } 

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

    /** 
    * A cell that contains a text field that is always shown. The text of the 
    * text field is bound to the underlying data. 
    */ 
    public static class AlwaysEditingCell extends TableCell<ObservableList<StringProperty>, String> { 

     private final TextField textField; 

     public AlwaysEditingCell(int columnIndex) { 

      textField = new TextField(); 

      this.emptyProperty().addListener((obs, wasEmpty, isNowEmpty) -> { 
       if (isNowEmpty) { 
        setGraphic(null); 
       } else { 
        setGraphic(textField); 
       } 
      }); 

      // The index is not changed until tableData is instantiated, so this 
      // ensure the we wont get a NullPointerException when we do the 
      // binding. 
      this.indexProperty().addListener((obs, oldValue, newValue) -> { 

       ObservableList<ObservableList<StringProperty>> tableData = getTableView().getItems(); 
       int oldIndex = oldValue.intValue(); 
       if (oldIndex >= 0 && oldIndex < tableData.size()) { 
        textField.textProperty().unbindBidirectional(tableData.get(oldIndex).get(columnIndex)); 
       } 
       int newIndex = newValue.intValue(); 
       if (newIndex >= 0 && newIndex < tableData.size()) { 
        textField.textProperty().bindBidirectional(tableData.get(newIndex).get(columnIndex)); 
        setGraphic(textField); 
       } else { 
        setGraphic(null); 
       } 

      }); 
     } 
    } 

    /** 
    * A cell containing a checkbox. The checkbox represent the underlying value 
    * in the cell. If the cell value is 0, the checkbox is unchecked. Checking 
    * or unchecking the checkbox will change the underlying value. 
    */ 
    public static class CheckBoxCell extends TableCell<ObservableList<StringProperty>, String> { 

     private final CheckBox box; 
     private ObservableList<ObservableList<StringProperty>> tableData; 

     public CheckBoxCell(int columnIndex) { 

      this.box = new CheckBox(); 

      this.emptyProperty().addListener((obs, wasEmpty, isNowEmpty) -> { 
       if (isNowEmpty) { 
        setGraphic(null); 
       } else { 
        setGraphic(box); 
       } 
      }); 

      this.indexProperty().addListener((obs, oldValue, newValue) -> { 

       tableData = getTableView().getItems(); 

       int newIndex = newValue.intValue(); 
       if (newIndex >= 0 && newIndex < tableData.size()) { 
        // If active value is "1", the check box will be set to 
        // selected. 
        box.setSelected(tableData.get(getIndex()).get(columnIndex).equals("1")); 

        // We add a listener to the selected property. This will 
        // allow us to execute code every time the check box is 
        // selected or deselected. 
        box.selectedProperty().addListener((observable, oldVal, newVal) -> { 
         if (newVal) { 
          // If newValue is true the checkBox is selected, and 
          // we set the corresponding cell value to "1". 
          tableData.get(getIndex()).get(columnIndex).set("1"); 
         } else { 
          // Otherwise we set it to "0". 
          tableData.get(getIndex()).get(columnIndex).set("0"); 
         } 
        }); 

        setGraphic(box); 
       } else { 
        setGraphic(null); 
       } 

      }); 
     } 
    } 
} 

當按下TAB而聚焦TextField一個TableCell內部,焦點被正確地移動到下一個控制。但是,如果一個CheckBox一個TableCell內聚焦,焦點移動到TableView,而不是第一Control下一個Control。 SHIFT + TAB同時注重一個CheckBox將焦點移動到TableView最後的控制。如果我在TableView之外添加TextField,那麼在對齊CheckBox時,SHIFT + TAB實際上將會集中該TextField,而TAB行爲仍然至少將焦點保持在TableView之內。 CheckBox以某種方式打破了遍歷順序。

這是因爲TextFieldCheckBox奇怪,我似乎有相同的TAB功能實現的,由於遍歷順序是第一個例子是正確的。我猜的是繼承Control類。

有誰知道這事?我試圖尋找某種EventFilter或聽衆的TAB和SHIFT + TAB命令ControlTextFieldCheckBoxTextInputControl乃至Scene源裏面的源代碼,但我不能在任何地方找到它。

我也試過爲CheckBox單元實施我自己的TAB功能,最終導致另一個issue

回答

0

我掙扎了很多有同樣的問題。我終於避開它通過設置:

checkBox.setFocusTraversable(false); 

this.setFocusTraversable(false); 

在我自己的實現BooleanCell的。 表橫越在可編輯的字段和複選框始終在我的實現啓用。但將複選框設置爲禁用意味着您必須雙擊才能更改該值。這將是奇怪的行爲。