java JavaFX 中 tableview 单元格中的组合框

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35131428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 23:46:32  来源:igfitidea点击:

ComboBox in a tableview cell in JavaFX

javajavafxcombobox

提问by noobCoder

I'm trying to a add a Combo Boxto my Table View:

我正在尝试添加一个Combo Box到我的Table View

Basically I have a class called TableViewTest that stores a name and a description, I can display theses names and descriptions in a Table Viewno bother, but what I want to do is add a third column with each cell having a Combo Boxso that the user can select one from a number of options for each person.

基本上我有一个名为 TableViewTest 的类,它存储名称和描述,我可以Table View毫不费力地显示这些名称和描述,但我想要做的是添加第三列,每个单元格都有一个,Combo Box以便用户可以选择一个从每个人的多个选项。

So far I have created an ObservableListof type Stringwith some values and added them to a ComboBoxobject. Does anyone know a way for me to add this Combo Boxto the table?

到目前为止,我已经创建了一个具有一些值ObservableList的类型String并将它们添加到一个ComboBox对象中。有谁知道我可以将它添加Combo Box到表格中的方法吗?

Also bear in mind this code is pretty rough and I'm just trying to get something working and I'll be refactoring the code at a later date.

还要记住,这段代码非常粗糙,我只是想让一些东西工作,我将在以后重构代码。

ObservableList<TableViewTest> products = FXCollections.observableArrayList();

    for(int i = 0; i < b.length; i++){

        // random String values
        products.add(new TableViewTest(b[i], a[i]));
    }

ObservableList<String> options = FXCollections.observableArrayList(
                                "1",
                                "2",
                                "3"
                                );
final ComboBox comboBox = new ComboBox(options);

TableColumn<TableViewTest, String> nameColumn = new TableColumn<> ("Name");
nameColumn.setMinWidth(200);
nameColumn.setCellValueFactory(new PropertyValueFactory<TableViewTest, String>("name"));

                //price Column
                //Stock Column
TableColumn<TableViewTest, String> StockColumn = new TableColumn<> ("Stock");
StockColumn.setMinWidth(150);
StockColumn.setCellValueFactory(new PropertyValueFactory<TableViewTest, String>("description"));


TableColumn<Object,ComboBox> PriceColumn;
PriceColumn = new TableColumn<>("Source");
PriceColumn.setMinWidth(150);
   //PriceColumn.setCellValueFactory(new PropertyValueFactory<>
   //(options));

   //PriceColumn.setCellFactory(ComboBoxTableCell.forTableColumn(new 
   //DefaultStringConverter(), options));


   //PriceColumn.setCellFactory(ComboBoxTableCell.forTableColumn( 
   //comboBox));

TableView<TableViewTest> table = new TableView<>();

table.setItems(products);
table.getColumns().addAll(nameColumn, StockColumn, PriceColumn);

回答by James_D

The types for your table column are always the type of the item in each row (i.e. the same as the type you use for the table view) for the first type parameter, and the type of the (current) value for each cell in the column for the second parameter. So if your table view has type TableViewTest, and your combo box is selecting Strings, you should have:

表格列的类型始终是第一个类型参数的每行中项目的类型(即与您用于表格视图的类型相同),以及每个单元格的(当前)值的类型第二个参数的列。因此,如果您的 table view 具有 type TableViewTest,并且您的组合框正在选择Strings,则您应该:

TableColumn<TableViewTest, String> priceColumn ;

The cell value factory should still map to a property in the TableViewTestclass, i.e. assuming you have:

单元格值工厂仍应映射到TableViewTest类中的属性,即假设您有:

public class TableViewTest {

    // ...

    public StringProperty priceProperty() {
        // ...
    }

    // ...
}

then you can do:

那么你可以这样做:

priceColumn.setCellValueFactory(new PropertyValueFactory<>("price"));

or (much better):

或(更好):

priceColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty());

Then you can just do:

然后你可以这样做:

priceColumn.setCellFactory(ComboBoxTableCell.forTableColumn(options));

Here's a SSCCE:

这是一个 SSCCE:

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.ComboBoxTableCell;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class TableWithComboBoxExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        TableView<Contact> contactTable = new TableView<>();
        contactTable.setEditable(true);

        TableColumn<Contact, String> nameCol = new TableColumn<>("Name");
        nameCol.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
        nameCol.setCellFactory(TextFieldTableCell.forTableColumn());
        contactTable.getColumns().add(nameCol);


        TableColumn<Contact, String> categoryCol = new TableColumn<>("Category");
        categoryCol.setCellValueFactory(cellData -> cellData.getValue().categoryProperty());

        categoryCol.setCellFactory(ComboBoxTableCell.forTableColumn("Friends", "Family", "Work Contacts"));

        contactTable.getColumns().add(categoryCol);

        contactTable.getItems().addAll(
            new Contact("Bill Gates", "Work Contacts"),
            new Contact("Barack Obama", "Friends"),
            new Contact("Tim Cook", "Work Contacts")
        );

        Scene scene = new Scene(new BorderPane(contactTable), 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static class Contact {
        private final StringProperty name = new SimpleStringProperty();
        private final StringProperty category = new SimpleStringProperty();

        public Contact(String name, String category) {
            setName(name);
            setCategory(category);
        }

        public final StringProperty nameProperty() {
            return this.name;
        }


        public final String getName() {
            return this.nameProperty().get();
        }


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


        public final StringProperty categoryProperty() {
            return this.category;
        }


        public final String getCategory() {
            return this.categoryProperty().get();
        }


        public final void setCategory(final String category) {
            this.categoryProperty().set(category);
        }

    }

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

回答by fabian

James_D's answer works well, but requires the user to click on the item to see the ComboBox. If you want to have ComboBoxes in a column, that are always shown, you have to use a custom cellFactory:

James_D 的回答效果很好,但需要用户单击该项目才能看到ComboBox. 如果您想ComboBox在列中包含始终显示的 es,则必须使用自定义cellFactory

Example:

例子:

public class TableViewTest {

    ...

    private final StringProperty option = new SimpleStringProperty();

    public String getOption() {
        return option.get();
    }

    public void setOption(String value) {
        option.set(value);
    }

    public StringProperty optionProperty() {
        return option;
    }

}
    TableColumn<TableViewTest, StringProperty> column = new TableColumn<>("option");
    column.setCellValueFactory(i -> {
        final StringProperty value = i.getValue().optionProperty();
        // binding to constant value
        return Bindings.createObjectBinding(() -> value);
    });

    column.setCellFactory(col -> {
        TableCell<TableViewTest, StringProperty> c = new TableCell<>();
        final ComboBox<String> comboBox = new ComboBox<>(options);
        c.itemProperty().addListener((observable, oldValue, newValue) -> {
            if (oldValue != null) {
                comboBox.valueProperty().unbindBidirectional(oldValue);
            }
            if (newValue != null) {
                comboBox.valueProperty().bindBidirectional(newValue);
            }
        });
        c.graphicProperty().bind(Bindings.when(c.emptyProperty()).then((Node) null).otherwise(comboBox));
        return c;
    });