Zelphir Kaltstahl
Zelphir Kaltstahl

Reputation: 6189

JavaFX tableview resizeable and unresizeable column

I have a TableView and in this TableView, there are 5 columns. One of the columns only contains the number of the row in the TableView, it simply counts them. The following behavior is what I want to achieve:

  1. Number Column shall have a width fitting its content
  2. Number Column shall not be resizeable
  3. The other columns shall be resizeable
  4. The other columns can and shall truncate their content when it is too long, so that they fit into the area of the TableView and no horizontal scrollbar is visible

I have 5 TableView column, which I created like this:

TableColumn numberColumn = new TableColumn("#");
numberColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Vocable, String>, ObservableValue<String>>() {
    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<Vocable, String> vocableCellDataFeature) {
        return new ReadOnlyObjectWrapper(getItems().indexOf(vocableCellDataFeature.getValue()) + "");
    }
});
numberColumn.setResizable(false);
//numberColumn.setMaxWidth(numberColumn.getMaxWidth()-20);

TableColumn<Vocable, String> firstLanguageColumn = new TableColumn<>(Settings.FIRST_LANGUAGE);
firstLanguageColumn.setCellValueFactory(new PropertyValueFactory<>("firstLanguageTranslationsAsString"));
firstLanguageColumn.setMinWidth(100);

TableColumn<Vocable, String> firstLanguagePhoneticScriptColumn = new TableColumn<>(Settings.FIRST_LANGUAGE_PHONETIC_SCRIPT);
firstLanguagePhoneticScriptColumn.setCellValueFactory(new PropertyValueFactory<>("firstLanguagePhoneticScriptsAsString"));
firstLanguagePhoneticScriptColumn.setMinWidth(100);

TableColumn<Vocable, String> secondLanguagePhoneticScriptColumn = new TableColumn<>(Settings.SECOND_LANGUAGE_PHONETIC_SCRIPT);
secondLanguagePhoneticScriptColumn.setCellValueFactory(new PropertyValueFactory<>("secondLanguagePhoneticScriptsAsString"));
secondLanguagePhoneticScriptColumn.setMinWidth(100);

TableColumn<Vocable, String> secondLanguageColumn = new TableColumn<>(Settings.SECOND_LANGUAGE);
secondLanguageColumn.setCellValueFactory(new PropertyValueFactory<>("secondLanguageTranslationsAsString"));
secondLanguageColumn.setMinWidth(100);

getColumns().add(numberColumn);
getColumns().add(firstLanguageColumn);
getColumns().add(firstLanguagePhoneticScriptColumn);
getColumns().add(secondLanguagePhoneticScriptColumn);
getColumns().add(secondLanguageColumn);

getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

So my question is: How can I achieve this kind of behavior in the JavaFX TableView? Is it possible?

Upvotes: 1

Views: 3805

Answers (1)

brian
brian

Reputation: 10969

Bind the column max and min widths to a fraction of the TableView width. Make the fractions add up to 1

    ?Col.maxWidthProperty().bind(tableView.widthProperty().multiply(.25));
    ?Col.minWidthProperty().bind(amountCol.maxWidthProperty());

You should really do something like this

    ?Col.minWidthProperty().bind(tableView.widthProperty().subtract(20).multiply(.25));

except that causes an error. It says A bound value cannot be set. but that's not true as it only has a problem with subtraction resulting in <0. .subtract(-10) works fine, except for not being what you want.

There must be a bug in the bindings somewhere.

edit: If you resize columns bigger than the table then you'll get a scroll bar. So when one gets bigger, others have to get smaller. I find this annoying when all columns change some percentage but maybe like this is acceptable.

import javafx.application.Application;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;

public class TableTest extends Application {

    @Override
    public void start(Stage stage) {
        ObservableList<LineItem> items = FXCollections.observableArrayList();
        items.addAll(new LineItem(1,"string1","string2",123.45),
                     new LineItem(1,"string1","string2",123.45),
                     new LineItem(1,"string1","string2",123.45));

        TableView<LineItem> tableView = new TableView<>(items);

        TableColumn<LineItem,String> numCol = new TableColumn<>("num");
        TableColumn<LineItem,String> descCol = new TableColumn<>("desc");
        TableColumn<LineItem,String> nameCol = new TableColumn<>("name");
        TableColumn<LineItem, Double> amountCol = new TableColumn<>("amount");

        numCol.setCellValueFactory(new PropertyValueFactory<>("num"));
        descCol.setCellValueFactory(new PropertyValueFactory<>("desc"));
        nameCol.setCellValueFactory(new PropertyValueFactory<>("name"));
        amountCol.setCellValueFactory(new PropertyValueFactory<>("amount"));

        tableView.getColumns().addAll(numCol,descCol,nameCol,amountCol);

        //col width logic, or lack thereof
        numCol.setPrefWidth(20);
        numCol.setResizable(false);
        tableView.setColumnResizePolicy((TableView.ResizeFeatures param) -> {
            if (param.getColumn() == null )return false;
            double delta = param.getDelta();
            ObservableList<TableColumn> cols = param.getTable().getColumns();
            int colIdx = cols.indexOf(param.getColumn());
            param.getColumn().setMinWidth(param.getColumn().getWidth() + delta);
            param.getColumn().setMaxWidth(param.getColumn().getWidth() + delta);
            if (colIdx < cols.size() -1){
                cols.get(colIdx+1).setMinWidth(cols.get(colIdx+1).getWidth() - delta);
                cols.get(colIdx+1).setMaxWidth(cols.get(colIdx+1).getWidth() - delta);
            } else {
                stage.setWidth(stage.getWidth() + delta);
            }
            return true;
        });

        Scene scene = new Scene(tableView);
        stage.setScene(scene);
        stage.show();
    }


    public class LineItem {

        private final SimpleIntegerProperty num = new SimpleIntegerProperty();
        private final SimpleStringProperty desc = new SimpleStringProperty();
        private final SimpleStringProperty name = new SimpleStringProperty();
        private final SimpleDoubleProperty amount = new SimpleDoubleProperty();

        public SimpleIntegerProperty numProperty() {return num;}
        public SimpleStringProperty descProperty() {return desc;}
        public SimpleStringProperty nameProperty() {return name;}
        public SimpleDoubleProperty amountProperty() {return amount;}

        public LineItem(int num, String desc, String name, double amount) {
            this.num.set(num); 
            this.desc.set(desc);
            this.name.set(name);
            this.amount.set(amount);
        }
    }
}

Upvotes: 0

Related Questions