This discussion is archived
12 Replies Latest reply: Jan 22, 2013 12:06 PM by abhinay_a RSS

Creating a dynamic editable column

abhinay_a Newbie
Currently Being Moderated
I was trying to make my dynamic columns as editable. The problem is my dynamic columns are nested columns.

Now editable column works fine when I have diff columns with different name. E.g. col1, col2, col3 (not nested)

Or I have nested columns like "col"(parent) having two columns col1 and col2.

But, when I use them in a dynamic columns in which each of them have the same name, here in the below example, each of them having the same name "col", I can edit each of them, but the textfield never vanishes, when I click ENTER.


Suppose i have a editable column with name col :
for (final CategoryTypeVO type : typeList)
                {
                       TableColumn<ItemVO, Integer> col = new TableColumn<ItemVO, Integer>(type.getTypeName());
                      col.setMinWidth(100);
                      col.setEditable(true);
                      col.setCellFactory(cellFactory);
                     
                     
                      col.setOnEditCommit(
                               new EventHandler<TableColumn.CellEditEvent<ItemVO, Integer>>() {
                               public void handle(TableColumn.CellEditEvent<ItemVO, Integer> t) {
                               ((ItemVO)t.getTableView().getItems().get(
                               t.getTablePosition().getRow())).getListType().get(type.getTypeId()).setQuantity(t.getNewValue());
                               }
                               });
                       quantity.getColumns().add(col);
                     }
and cellfactory as :
final Callback<TableColumn<ItemVO, Integer>, TableCell<ItemVO, Integer>> cellFactory = new Callback<TableColumn<ItemVO, Integer>, TableCell<ItemVO, Integer>>() {
                    public TableCell call(TableColumn p) {
                         return new EditingCell();
                    }
               };
and Editing class as
class EditingCell extends TableCell<ItemVO, Integer> {
           
           private TextField textField;
          
           public EditingCell() {}
          
           @Override
           public void startEdit() {
               super.startEdit();
              
               if (textField == null) {
                   createTextField();
               }
              
               
               setGraphic(textField);
               setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
               textField.selectAll();
               Platform.runLater(new Runnable() {
                   @Override
                   public void run() {
                       textField.requestFocus();
                   }
              });
           }
          
           @Override
           public void cancelEdit() {
               super.cancelEdit();
              
               setText(String.valueOf(getItem()));
               setContentDisplay(ContentDisplay.TEXT_ONLY);
           }
      
           @Override
           public void updateItem(Integer item, boolean empty) {
               super.updateItem(item, empty);
              
               if (empty) {
                   setText(null);
                   setGraphic(null);
               } else {
                   if (isEditing()) {
                       if (textField != null) {
                           textField.setText(getString());
                       }
                       setGraphic(textField);
                       setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                   } else {
                       setText(getString());
                       setContentDisplay(ContentDisplay.TEXT_ONLY);
                   }
               }
           }
           
          
           
      
           private void createTextField() {
               textField = new TextField();
               //textField.setText(getString());
               textField.setText("0");
               textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()*2);
               
               textField.focusedProperty().addListener(new ChangeListener<Boolean>() {

                      @Override
                      public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
                          if (!arg2) {
                              commitEdit(Integer.parseInt(textField.getText()));
                          }
                      }
                  });
               
               textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
                   @Override public void handle(KeyEvent t) {
                       if (t.getCode() == KeyCode.ENTER) {
                           commitEdit(Integer.parseInt(textField.getText()));
                       } else if (t.getCode() == KeyCode.ESCAPE) {
                           cancelEdit();
                       }
                   }
               });
           }

          
           private String getString() {
               return getItem() == null ? "" : getItem().toString();
           }
Now what happens is this thing works fine if i have separate columns with separate names. But when it comes to dynamic columns it fails, once i edit a cell, the text field never leaves its place.It remains stuck in the cell. Any help !!

Edited by: abhinay_a on Jan 21, 2013 12:31 AM
  • 1. Re: Creating a dynamic editable column
    abhinay_a Newbie
    Currently Being Moderated
    Does anyone knows anything about this ?
  • 2. Re: Creating a dynamic editable column
    Narayan Pro
    Currently Being Moderated
    Ah..sorry you seems to have two thread having similarities got confused.

    Edited by: Narayan on Jan 22, 2013 11:30 AM
  • 3. Re: Creating a dynamic editable column
    abhinay_a Newbie
    Currently Being Moderated
    But the thread is not answered !!
  • 4. Re: Creating a dynamic editable column
    Narayan Pro
    Currently Being Moderated
    I think you already had looked over the Dynamic Table tutorial that I have given. It describes all things of dynamic columns making too.

    Thanks
    Narayan
  • 5. Re: Creating a dynamic editable column
    abhinay_a Newbie
    Currently Being Moderated
    yes i have, but if you have a better look at the question then you might see that i have successfully created the dyanmic columns, I am stuck when I am trying to edit them.

    When I have just 1 column the editing works fine i.e. I get a textfield, can change the value in it and then when i press enter, the value is stored in it.

    Butwhen i have multiple columns, clicking on a Tablecell, creates a textfield but this textfield doesnt get conveted into a tablecell when i click enter and then when i click on another tablecell, i get the same result and the textfield never goes away !!

    I guess now you will have better undertsnading of what I am asking here ..

    Edited by: abhinay_a on Jan 21, 2013 10:07 PM
  • 6. Re: Creating a dynamic editable column
    Narayan Pro
    Currently Being Moderated
    Hi abhinay,
    I think the code above is alright and correct.
    Do you get any exceptions? while using multi columns . I doubt on the ItemVO class.

    Thanks
  • 7. Re: Creating a dynamic editable column
    abhinay_a Newbie
    Currently Being Moderated
    No i dont remeber any exceptions, still i will comfirm it once I am back home.

    To throw some more light, my ItemVO class is as follows :
    public class ItemVO 
    {
         private String itemId;
         private String itemName;
         private String categoryId;
         private ObservableMap<String,ItemTypeVO> listType;
                    //getters and setters
    }
    and My ItemTypeVO is
    public class ItemTypeVO 
    {
         private String typeId;
         private String itemId;
         private Integer quantity;
         private Integer mrp;
                    //getters and setters
    }
    My types depend on the category, so all the items in the category will have same types.

    Each row has a different item.

    Here i am trying to display the "item name" in one column and the quantity of each type in another, so my "quantity" column has nested columns depending on the types.

    Now, i want the user to enter the quantity of each type of an item that has been sold in the table and then persist it into the DB.

    I don't know, but, i was guessing that because all the nested columns are defined by the name "col" (you can see that in the code above), i am having the problem.
  • 8. Re: Creating a dynamic editable column
    James_D Guru
    Currently Being Moderated
    Not sure what is wrong in your code, but it's easier to use TextFieldTableCell than building your own TableCell from scratch.

    This modification to the example I posted in How to create a tableview for this ?? works for me:
    package itemtable;
    
    import javafx.application.Application;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.scene.Scene;
    import javafx.scene.control.ChoiceBox;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableColumn.CellDataFeatures;
    import javafx.scene.control.TableView;
    import javafx.scene.control.cell.PropertyValueFactory;
    import javafx.scene.control.cell.TextFieldTableCell;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
    import javafx.util.Callback;
    import javafx.util.converter.NumberStringConverter;
    
    public class ItemTable extends Application {
    
      @Override
      public void start(Stage primaryStage) {
        final DAO dao = new MockDAO();
        final ChoiceBox<Category> choiceBox = new ChoiceBox<Category>();
        choiceBox.getItems().setAll(dao.getCategories());
    
        final TableView<Item> table = new TableView<Item>();
        
        // Make table editable:
        table.setEditable(true);
        
        final TableColumn<Item, String> nameCol = new TableColumn<Item, String>("Name");
        nameCol.setCellValueFactory(new PropertyValueFactory<Item, String>("name"));
        nameCol.setCellFactory(TextFieldTableCell.<Item>forTableColumn());
        final TableColumn<Item, Double> priceCol = new TableColumn<Item, Double>("Price");
        table.getColumns().addAll(nameCol, priceCol);
    
        choiceBox.getSelectionModel().selectedItemProperty()
            .addListener(new ChangeListener<Category>() {
              @Override
              public void changed(ObservableValue<? extends Category> observable, Category oldValue, Category newValue) {
                table.getItems().clear();
                priceCol.getColumns().clear();
                for (final Type type : newValue.getTypes()) {
                  final TableColumn<Item, Number> col = new TableColumn<Item, Number>(type.getName());
                  col.setCellValueFactory(new Callback<CellDataFeatures<Item, Number>, ObservableValue<Number>>() {
                    @Override
                    public ObservableValue<Number> call(CellDataFeatures<Item, Number> cellData) {
                      Item item = cellData.getValue();
                      if (item == null) {
                        return null;
                      } else {
                        return item.priceProperty(type);
                      }
                    }
                  });
                  
                  // Make column editable:
                  col.setEditable(true);
                  col.setCellFactory(TextFieldTableCell.<Item, Number>forTableColumn(new NumberStringConverter()));
                  
                  priceCol.getColumns().add(col);
                }
                table.getItems().setAll(dao.getItemsByCategory(newValue));
              }
            });
    
        BorderPane root = new BorderPane();
        root.setTop(choiceBox);
        root.setCenter(table);
    
        Scene scene = new Scene(root, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
      }
    
      public static void main(String[] args) {
        launch(args);
      }
    }
    Edited by: James_D on Jan 22, 2013 7:22 AM
  • 9. Re: Creating a dynamic editable column
    James_D Guru
    Currently Being Moderated
    This is a guess, but the problem may be that you're using the same cell factory instance for all the columns. Does it fix it if you move the definition of the cellFactory variable inside the for loop that creates the columns? Something like
    for (final CategoryTypeVO type : typeList)
                    {
                           TableColumn<ItemVO, Integer> col = new TableColumn<ItemVO, Integer>(type.getTypeName());
                          col.setMinWidth(100);
                          col.setEditable(true);
    
                          final Callback<TableColumn<ItemVO, Integer>, TableCell<ItemVO, Integer>> cellFactory = new Callback<TableColumn<ItemVO, Integer>, TableCell<ItemVO, Integer>>() {
                             public TableCell call(TableColumn p) {
                                 return new EditingCell();
                             }
                            };
                          col.setCellFactory(cellFactory);
                         
                          col.setOnEditCommit(
                                   new EventHandler<TableColumn.CellEditEvent<ItemVO, Integer>>() {
                                   public void handle(TableColumn.CellEditEvent<ItemVO, Integer> t) {
                                   ((ItemVO)t.getTableView().getItems().get(
                                   t.getTablePosition().getRow())).getListType().get(type.getTypeId()).setQuantity(t.getNewValue());
                                   }
                                   });
                           quantity.getColumns().add(col);
                         }
  • 10. Re: Creating a dynamic editable column
    abhinay_a Newbie
    Currently Being Moderated
    hey guys i got the error, i wasn't using
    col.setCellValueFactory(new Callback<CellDataFeatures<ItemVO, Integer>, ObservableValue<Integer>>() {
    in my code. Thanks James only after you quoted the code, i realized my mistake.

    Can you tell me why is it important to use this code when i just want to fill the cell with my own data ??

    Edited by: abhinay_a on Jan 22, 2013 11:31 AM
  • 11. Re: Creating a dynamic editable column
    James_D Guru
    Currently Being Moderated
    The table holds a list of items; in your case a list of ItemVO instances. Each one represents a row in the table. You need to tell each column how to compute the value to display given one of these items. In simple cases, the column maps to a property, so you can use the convenience PropertyValueFactory class and just specify the name of the property. In your case the data is more complex; you need to retrieve a map from the object and retrieve the data to display from your map. So you need to give it an implementation of Callback which specifies how to do this.
  • 12. Re: Creating a dynamic editable column
    abhinay_a Newbie
    Currently Being Moderated
    ohh..got ya..

    Thanks a lot james and you too narayan ! :)

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points