Taelsin
Taelsin

Reputation: 1080

How to determine the direction and position of a combo box when opening it programatically in JavaFX?

I'm having issues with positioning and direction when programmatically opening a combo box from withing a table row. Because the combo box is within a table row in a table the user would have to click a total of three times in one cell to open the combo box. For convenience I've created a custom class that allows for one click editing of the combo box. This works wonderfully! However when the combo box opens the top left corner of the resulting dialogue is tucked into the top left corner of the selected cell and not just below and aligned with the combo box. Eg:

Misaligned combo box

This issue corrects itself when the user scrolls the combo box either by using the mouse wheel or by clicking on the scroll bar and moving it.

Another interesting issue is that the combo box will not always open in the correct direction. In one particular table at the bottom of my UI the combo box will open downwards in rows one through five. In rows four and five, once the user scrolls, the combo box will move to the correct position above the combo box. Example of the combo box showing in row 4:

Combo box below the UI bounds

Is there any way I can align the combo box correctly after I've run the combobox.show() command? Not all of my combo boxes have enough items in them to scroll so programmatically scrolling the combo box will not work for all of my combo boxes.

Here is my custom tablecell class.

private class MyCustomComboBoxTableCell extends TableCell<MyCustomRow, String>{

    private final ComboBox<String> comboBox;

    public MyCustomComboBoxTableCell(ObservableList<String> items){
        this.comboBox = new ComboBox<String>(items);

        comboBox.setOnShown(new EventHandler<Event>(){
            @Override
            public void handle(Event event) {
                getTableView().edit(getIndex(), getTableColumn());
                getTableView().getSelectionModel().clearSelection();
            }
        });

        comboBox.valueProperty().addListener(new ChangeListener<String>(){
            @Override
            public void changed(ObservableValue obs, String oldValue, String newValue) {
                if(newValue != null && !newValue.equals(oldValue)){
                    commitEdit(comboBox.getSelectionModel().getSelectedItem());
                }
            }
        });

        addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>(){
            @Override
            public void handle(MouseEvent event){
                if(getIndex() < getTableView().getItems().size()){
                    startEdit();
                    comboBox.show();
                }
            }
        });
    }

    @Override
    public void startEdit(){
        super.startEdit();

        setGraphic(comboBox);
        setText(null);
    }

    @Override
    public void cancelEdit(){
        super.cancelEdit();

        setText((String)getItem());
        setGraphic(null);
    }

    @Override 
    public void updateItem(String item, boolean empty){
        super.updateItem(item, empty);
        if(empty){
            setGraphic(null);
        } else {
            if(isEditing()){
                setGraphic(comboBox);
                setText(null);
            } else {
                setGraphic(null);
                setText(getItem());
            }
        }
    }
}

Upvotes: 0

Views: 977

Answers (1)

fabian
fabian

Reputation: 82461

The ComboBox has not been layouted when you start the edit. The popup will be shown based on the current bounds of the ComboBox, which means those bounds will most likely be wrong.

Triggering a layout pass on the TableView should fix this issue:

addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent event) {
        if (getIndex() < getTableView().getItems().size()) {
            startEdit();

            // trigger layout pass
            getTableView().applyCss();
            getTableView().layout();

            comboBox.show();
        }
    }
});

Upvotes: 1

Related Questions