Checkbox TableCell中的复选框会破坏遍历顺序

Checkbox TableCell中的复选框会破坏遍历顺序,checkbox,javafx,tableview,traversal,tablecell,Checkbox,Javafx,Tableview,Traversal,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 A

考虑以下示例:

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();
    }
}
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和SHIFT+TAB命令遍历不同的控件,并且可以正常工作

但是,如果在
表视图的表单元格中有相同的控件,则
复选框将打破遍历顺序。下面的示例演示了这一点:

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();
    }
}
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);
                }

            });
        }
    }
}
导入javafx.application.application;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.scene.scene;
导入javafx.scene.control.CheckBox;
导入javafx.scene.control.TableCell;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.control.TextField;
导入javafx.stage.stage;
公共类AlwaysEditableTable扩展应用程序{
公众假期开始(阶段){
TableView table=新TableView();
table.setEditable(true);
table.getSelectionModel().setCellSelectionEnabled(true);
表3.setPrefWidth(505);
//虚拟柱
ObservableList columns=FXCollections.observableArrayList(“Column1”、“Column2”、“Column3”、“Column4”,
“第5栏”);
//虚拟数据
ObservableList row1=FXCollections.observableArrayList(新的SimpleStringProperty(“Cell1”),
新SimpleStringProperty(“Cell2”)、新SimpleStringProperty(“0”)、新SimpleStringProperty(“Cell4”),
新SimpleStringProperty(“1”);
ObservableList data=FXCollections.observableArrayList();
添加数据(第1行);
对于(int i=0;iparam.getValue().get(j));
列设置宽度(100);
如果(i==2 | | i==4){
col.setCellFactory(e->new CheckBoxCell(j));
}否则{
col.setCellFactory(e->new AlwaysEditingCell(j));
}
table.getColumns().add(col);
}
表2.设置项目(数据);
场景=新场景(表);
舞台场景;
stage.show();
}
公共静态void main(字符串[]args){
发射();
}
/**
*包含始终显示的文本字段的单元格
*文本字段绑定到基础数据。
*/
公共静态类AlwaysEditingCell扩展TableCell{
私有最终文本字段文本字段;
公共AlwaysEditingCell(int columnIndex){
textField=新的textField();
this.emptyProperty().addListener((obs,waspempty,isNowEmpty)->{
如果(现在为空){
设置图形(空);
}否则{
设置图形(文本字段);
}
});
//在实例化tableData之前,不会更改索引,因此
//确保在执行以下操作时不会出现NullPointerException
//绑定。
this.indexProperty().addListener((obs、oldValue、newValue)->{
ObservableList tableData=getTableView().getItems();
int oldIndex=oldValue.intValue();
如果(oldIndex>=0&&oldIndex=0&&newIndex{
如果(现在为空){
设置图形(空);
}否则{
设置图形(框);
}
});
this.indexProperty().addListener((obs、oldValue、newValue)->{
tableData=getTableView().getItems();
int newIndex=newValue.intValue();
如果(newIndex>=0&&newIndex{
if(newVal){
//如果newValue为true,则选中复选框,并且
//我们将相应的单元格值设置为“1”。
tableData.get(getIndex()).get(columnIndex).set(“1”);
}否则{
//否则,我们将其设置为“0”。
tableData.get(getIndex()).get(columnIndex).set(“0”);
}
});
设置图形(框);
}否则{
设置图形(空);