79358915

Date: 2025-01-15 16:04:27
Score: 2
Natty:
Report link

I got the answer or may be something which works fine for me. Let me explain what i wanted. I wanted to create a TableView with features of commiting the editing TableCell when focused is lost. I used @James_D this link to have my own custom TableCell : https://gist.github.com/james-d/be5bbd6255a4640a5357#file-editcell-java-L109

Also, I needed that user can input only values in a particular range say 100 to 500. I used JavaFX TextFormatter class for that. With the help of TextFormatter, I was able to filter user input so that only Integer or Float values are allowed. I was also able to put upper range limit (here 500) with the help of TextFormatter. The real issue came with lower range limit because you cannot predict users mind. Say, if user types "12" and our range is 100 - 500, then I cannot predict whether user will commit it or will type more. This was the real problem. Then after posting it on StackOverflow, James_D suggested to put the checking logic in commitEdit() method. I did it and it worked for me. Below is the code for Custom TableCell :-

class CustomTableCell<S, T> extends TableCell<S, T> {
    private final TextField textField = new TextField();
    private final StringConverter<T> converter;
    private final TextFormatter<T> textFormatter;
    
    int MIN_RANGE_VALUE = 100;
    int MAX_RANGE_VALUE = 500;
    int MAX_DIGITS = 3;
    
    public CustomTableCell(StringConverter<T> converter) {
        this.converter = converter;
        
        itemProperty().addListener((obsVal, oldItem, newItem) -> {
            if(newItem == null) {
                setText(null);
            } else {
                setText(converter.toString(newItem));    
            }
        });
        setGraphic(textField);    
        setContentDisplay(ContentDisplay.TEXT_ONLY);
        
        textFormatter = new TextFormatter<>(flowFilter);
                   
        textField.setTextFormatter(new TextFormatter<>(flowFilter));
        
        textField.setOnAction(event -> {
            System.out.println("textField setOnAction called....");
            commitEdit(this.converter.fromString(textField.getText()));
            
            
        });
        
        textField.focusedProperty().addListener((obsVal, wasFocused, isNowFocused) -> {
            if(!isNowFocused) {
                System.out.println("focused lost.....");   
                System.out.println("textField.getText() : " +textField.getText());
                commitEdit(this.converter.fromString(textField.getText()));
                
               
            }
        });
        
        textField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
            if(event.getCode() == KeyCode.ESCAPE) {
                textField.setText(converter.toString(getItem()));
                cancelEdit();
                event.consume();
            } else if(event.getCode() == KeyCode.RIGHT) {
                getTableView().getSelectionModel().selectRightCell();
                event.consume();
            } else if(event.getCode() == KeyCode.LEFT) {
                getTableView().getSelectionModel().selectLeftCell();
                event.consume();
            } else if(event.getCode() == KeyCode.UP) {
                getTableView().getSelectionModel().selectAboveCell();
                event.consume();
            } else if(event.getCode() == KeyCode.DOWN) {
                getTableView().getSelectionModel().selectBelowCell();
                event.consume();
            }
        });
    }
     
    
    UnaryOperator<Change> flowFilter = change -> {
        String controlNewText =  change.getControlNewText();
        String text = change.getText();
        
        System.out.println("controlNetText : "+controlNewText);
        System.out.println("text : "+text);
         
        if(change.getControlNewText().isEmpty()) {
            System.out.println("empty returned....");
             return change;
         } else if (controlNewText.matches("\\d*") && controlNewText.length() <= MAX_DIGITS) {
             int val = Integer.parseInt(controlNewText);
             if( val <= MAX_RANGE_VALUE) {
                 System.out.println("max min range returned...");
                 return change;
             } 
         }
        System.out.println("textFormatter null returned....");
        return null;
    };
    
    
    public static final StringConverter<String> IDENTITY_CONVERTER = new StringConverter<String>() {
        @Override
        public String toString(String object) {
           return object;
        }

        @Override
        public String fromString(String string) {
           return string;
        }
        
    };
    
    //Convenience method for creating an EditCell for a String value
    public static CustomTableCell<ReceipeDataModel, Number> createStringCustomTableCell() {
        return new CustomTableCell<ReceipeDataModel, Number>(new NumberStringConverter());
    }
    
    
    //set the text of TextField and display graphic
    @Override
    public void startEdit() {
        super.startEdit();
        textField.setText(converter.toString(getItem()));
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        textField.requestFocus();
    }
    
    //revert to text display
    @Override
    public void cancelEdit() {
        super.cancelEdit();
        setContentDisplay(ContentDisplay.TEXT_ONLY);
    }
    
    //commits the edit. Update the property if possible and revert to text display
    @Override
    public void commitEdit(T item) {
        //below code for empty string and converter returns null
        if(item == null) {
            item = getItem();
        }
                    
        //below code for putting range limits
        if(item != null) {
            long val = (long)item;  
            System.out.println("inside min max range if.....");
            item = (val >= MIN_RANGE_VALUE && val <= MAX_RANGE_VALUE) ? item : getItem();
        }
                   
        //this block is necessary because by deafult mechanism return false for isEditng() method when focus is lost. 
        //By Default, Only when we click on same TableRow, does the lost focus commits, not when we click outside the tableRow
        if(item != null && ! isEditing() && !item.equals(getItem())) {
            TableView<S> table = getTableView();
            if(table != null) {
                TableColumn<S, T> col = getTableColumn();
                TablePosition<S, T> pos = new TablePosition<>(table, getIndex(), col);
                CellEditEvent<S, T> cellEditEvent = new CellEditEvent<>(table, pos, TableColumn.editCommitEvent(), item);
                Event.fireEvent(col, cellEditEvent);
            }
        }

        super.commitEdit(item);
        
        setContentDisplay(ContentDisplay.TEXT_ONLY);
    }
}
Reasons:
  • Blacklisted phrase (0.5): I need
  • Blacklisted phrase (1): StackOverflow
  • Blacklisted phrase (0.5): I cannot
  • Blacklisted phrase (1): this link
  • Whitelisted phrase (-1): it worked
  • Whitelisted phrase (-1): worked for me
  • Long answer (-1):
  • Has code block (-0.5):
  • User mentioned (1): @James_D
  • Self-answer (0.5):
  • Low reputation (1):
Posted by: codekun