JavaFx-为什么在滚动

时间:2017-07-10 20:06:08

标签: java javafx

我有一个包含两列的tableview。第一列只是由observableList填充,第二列在每个单元格中都有选择框。

我的问题是,当我从选择框中选择值并向下滚动以从另一个选择框中选择值并再次向上滚动然后选择的选定值的值重置。

以下是我的代码:

@FXML
private TableColumn<FileHeaders, ChoiceBox<String>> fileHeaders;
public void setFileHeaders(ObservableList<String> fileHeadersObservableList) {
    fileHeaders.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<FileHeaders, ChoiceBox<String>>, ObservableValue<ChoiceBox<String>>>() {
        @Override
        public ObservableValue<ChoiceBox<String>> call(TableColumn.CellDataFeatures<FileHeaders, ChoiceBox<String>> rawUdrsList) {
            ChoiceBox<String> choiceBox = new ChoiceBox<>();
            System.out.println(choiceBox);//this value print again and again when I scroll the tableview
            choiceBox.setItems(fileHeadersObservableList);
            choiceBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
                @Override
                public void changed(ObservableValue<? extends String> ov, String t, String valueFromChoiceBox) {
                    //write some code stuff     
                }
            });
            return new SimpleObjectProperty<ChoiceBox<String>>(choiceBox);
        }
    });
}

据我所知,每次滚动tableview时都会调用call方法,因此创建了新的choicebox并将其设置到tableview中。

我该如何解决这个问题, 我非常感谢你们的帮助。

由于

1 个答案:

答案 0 :(得分:1)

您的错误

cell value factory不应该返回一个节点,它应该只返回支持该单元格的相关数据属性。相反,节点应作为cell factory提供的表格单元格实现的一部分返回。

定义细胞工厂

makery tutorials提供了一个很好的示例,显示了单元格值工厂和单元工厂之间的使用差异。通常,当您需要自定义呈现单元格数据时,两者会组合使用。

但是,JavaFX已经预定义了帮助程序类:查看使用How do you create a table cell factory in JavaFX to display a ChoiceBox?ChoiceBoxTableCell。也许你的问题只是重复一遍。

背景

要了解ChoiceBoxTableCell如何从第一原理开始工作,您可以查看其source code。表格单元格是Labeled。标签可以同时包含文本和图形。文本标签用于在未编辑单元格时显示所选值。每当用户双击单元格进行编辑时,文本就会设置为null,而是显示标签的图形节点(在这种情况下是一个允许用户为正在编辑的单元格选择新值的选项框) 。编辑完成后,选择的新值将保存到基础后备数据值属性,显示切换回纯文本,单元格的图形将设置为null,以便不再显示。对于您的用例,只使用预定义的类而不是编写相同功能的自定义实现将更容易。

示例

下面的示例应用程序的输出,在用户两次点击由选择框支持的用户状态后,第一次单击突出显示该行,第二次单击显示该项目的编辑选项框:

sample choice box

演示使用ChoiceBoxTableCell的示例代码:

import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.*;
import javafx.stage.Stage;

public class TableChoices extends Application {

    @Override
    public void start(final Stage stage) throws Exception {
        ObservableList<User> data = createTestData();

        TableColumn<User, String> nameCol = new TableColumn<>("Name");
        nameCol.setCellValueFactory(new PropertyValueFactory<>("name"));

        TableColumn<User, UserState> stateCol = new TableColumn<>("State");
        stateCol.setCellValueFactory(new PropertyValueFactory<>("state"));
        stateCol.setCellFactory(
                ChoiceBoxTableCell.forTableColumn(UserState.values())
        );
        stateCol.setEditable(true);
        stateCol.setPrefWidth(100);
        stateCol.setOnEditCommit(
                (TableColumn.CellEditEvent<User, UserState> t) ->
                        t.getTableView()
                                .getItems()
                                .get(t.getTablePosition().getRow())
                                .setState(t.getNewValue())
        );

        TableView<User> tableView = new TableView<>(data);
        //noinspection unchecked
        tableView.getColumns().addAll(
                nameCol,
                stateCol
        );
        tableView.setPrefSize(170, 150);
        tableView.setEditable(true);

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

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

    public enum UserState {
        ACTIVE,
        LOCKED,
        DELETED
    }

    public static class User {
        private StringProperty name;
        private ObjectProperty<UserState> state;

        public User(String name, UserState state) {
            this.name = new SimpleStringProperty(name);
            this.state = new SimpleObjectProperty<>(state);
        }

        public String getName() {
            return name.get();
        }

        public StringProperty nameProperty() {
            return name;
        }

        public void setName(String name) {
            this.name.set(name);
        }

        public UserState getState() {
            return state.get();
        }

        public ObjectProperty<UserState> stateProperty() {
            return state;
        }

        public void setState(UserState state) {
            this.state.set(state);
        }
    }

    private ObservableList<User> createTestData() {
        return FXCollections.observableArrayList(
                new User("Jack", UserState.ACTIVE),
                new User("Jill", UserState.LOCKED),
                new User("Tom", UserState.DELETED),
                new User("Harry", UserState.ACTIVE)
        );
    }
}

我建议您仔细查看示例代码,并注意对表列使用setOnEditCommit处理程序,该处理程序更新后备数据以反映编辑后的值。如果没有这样的代码,那么编辑将不会被提交回支持数据(至少在Java 8中,JavaFX Table Tutorial注意到未来的JavaFX版本可能会使实现变得不那么笨重。)