Event on ComBox which inside TableView cell JavaFx?
Asked Answered
L

0

2

I have TableView and when my program start TableView has only one row, also I have ArrayList of ComboBoxes and create one ComboBox for each row in the TableView, when user edit (Product Name) cell (which should contain the ComboBox on it) program create ComboBox for this cell and set the ComboBox as cell graphic (when ComboBox created not removed from cell graphic), and when the user select item from the last row ComboBox the program must create one row, the program behave correctly for the first row ComboBox action but the second row it failed, note the last ComboBox only its action create one additional row not every ComboBox, this photo can help to illustrate my problem

enter image description here

this my code:

import javafx.application.Application;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.ComboBox;
    import javafx.scene.control.TableCell;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableView;
    import javafx.scene.control.cell.PropertyValueFactory;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;

    public class BillDesign extends Application
    {
        private final TableView <Products> tableProducts = new TableView();
        private final TableColumn serial = new TableColumn("Serial");
        private final TableColumn productName = new TableColumn("ProductName");
        private final ObservableList <Products> data = FXCollections.observableArrayList(new Products("1", ""),
                                                                                         new Products("2", ""),
                                                                                         new Products("3", ""),
                                                                                         new Products("4", ""));
        private final Button button = new Button("Click");

        @Override
        public void start(Stage stage)
        {
            serial.setEditable(true);
            serial.setCellValueFactory(new PropertyValueFactory("Serial"));

            productName.setEditable(true);
            productName.setCellValueFactory(new PropertyValueFactory("ProductName"));
            productName.setCellFactory(column -> new TableCell ()
            {
                private ComboBox comboBox;

                @Override
                public void startEdit()
                {
                    if(!isEmpty())
                    {
                        super.startEdit();

                        comboBox = new ComboBox();

                        comboBox.setPrefWidth(getWidth());
                        comboBox.setEditable(true);
                        comboBox.getItems().addAll("A", "B", "C");

                        setGraphic(comboBox);

                        comboBox.setOnAction(e ->
                        {
                            data.get(getIndex()).setProductName(comboBox.getSelectionModel().getSelectedItem().
                                                                toString());

                            if(getIndex() == data.size() - 1)
                            {
                                data.add(new Products(String.valueOf(data.size() + 1), ""));
                            }
                        });
                    }
                }
            });

            button.setOnMouseClicked(e ->
            {
                for(int i = 0; i < data.size(); i++)
                {
                    System.out.println("Name " + data.get(i).getProductName() + "\tSerial " + data.get(i).getSerial());
                }
            });

            tableProducts.setEditable(true);
            tableProducts.getColumns().addAll(serial, productName);
            tableProducts.setItems(data);

            VBox root = new VBox(tableProducts, button);
            Scene scene = new Scene(root);

            stage.setScene(scene);
            stage.show();
        }

        public class Products
        {
            private final SimpleStringProperty Serial;
            private final SimpleStringProperty ProductName;

            public Products(String serial, String productName)
            {
                this.Serial = new SimpleStringProperty(serial);
                this.ProductName = new SimpleStringProperty(productName);
            }

            public void setSerial(String serial)
            {
                Serial.set(serial);
            }

            public String getSerial()
            {
                return Serial.get();
            }

            public void setProductName(String productName)
            {
                ProductName.set(productName);
            }

            public String getProductName()
            {
                return ProductName.get();
            }
        }
    }
Luncheonette answered 9/3, 2020 at 10:40 Comment(9)
still don't get why you don't use ComboBoxTableCell? don't keep nodes that are used by the cell outside of the cell! Instead keep the data inside of the cell (comboBoxTableCell allows to pass-in a list of content, or update it on-the-fly). and still not following java naming conventions (which is unrelated :)Unsheathe
I don't know what you mean by java naming conventions, my code is minimal as you asked before?Luncheonette
yeah, code looks like a nice example :) if you don't know what anything is .. well, you are a developer with access to the internet, what hinders you to type java naming conventions into your favorite search engine .. field names should start with a lower-case latter.Unsheathe
now, my code follow java naming conventions i just read it nowLuncheonette
@Unsheathe anything wrong right now in my code?Luncheonette
Implementing your own cell requires an understanding of how tables use cells and how their life-cycle is implemented. You appear to be creating a combo box for every item in the data; which could potentially be a huge drain on resources and negates all the optimizations provided for you by the API. All you need here is product.setCellFactory(column -> new ComboBoxTableCell<>("A","B"));.Camphene
For the "create a new row when the item in the last row changes", you should simply add listeners to the appropriate property in the model class, and modify the data list, etc. This shouldn't be done from the cell.Camphene
how make this ("add listeners to the appropriate property in the model class")Luncheonette
@Unsheathe I tried what you said here "don't keep nodes that are used by the cell outside of the cell! Instead keep the data inside of the cell (comboBoxTableCell allows to pass-in a list of content, or update it on-the-fly)", but still the same problem (cells ComboBoxes are shifted) and I edit the code to show you, can know why this happen?Luncheonette

© 2022 - 2024 — McMap. All rights reserved.