0

I want to disable reordering for the first or last column in a tableView. I could disable for the first or for the last column, in two ways, so I cannot move the first/last column but both way let me to drag a another column to the first/last place. How can I prevent this. I want to put somehow a "barrier" there, to have a fixed column all time.

How I disable the firstColumn:

firstColumn.impl_setReorderable(false); // I know the method is @Deprecated  but it works :)

the other solution would be with reflection, to get the reference of the TableHeaderRow then disable the reordering. But the problem in this solution is that, it disables all of the columns for reordering while I want just for the first or the last one.

Any simple idea how can I do something like this?

Sunflame
  • 2,993
  • 4
  • 24
  • 48

1 Answers1

0

You could 'let' the reordering to take place and then listening for changes and at the end of the event you could rearrange the columns the way you like. A very useful post about reordering columns is this one ( well there are a lot of good answers you should consider have a look). So you could add a listener to your table's skin property and inside do the following :

table.skinProperty().addListener((obs, oldSkin, newSkin) -> {
    final TableHeaderRow header = (TableHeaderRow) table.lookup("TableHeaderRow");
    header.reorderingProperty().addListener((o, oldVal, newVal) -> {
        ObservableList columns = table.getColumns();

        // If the first columns is not in the first index change it
        if (columns.indexOf(firstNameCol) != 0) {
                columns.remove(firstNameCol);
                columns.add(0, firstNameCol);
            }
        // Use the same logic for the last column
        if (columns.indexOf(phoneCol) != columns.size() - 1) {
            columns.remove(phoneCol);
            columns.add(columns.size() , phoneCol);
        }
    });
});

Here is a full working example :

import com.sun.javafx.scene.control.skin.TableHeaderRow;

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class TestApp extends Application {

    private TableView<Person> table = new TableView<Person>();
    private final ObservableList<Person> data = FXCollections.observableArrayList(
            new Person("Jacob", "Smith", "jacob.smith@example.com", "845-548-600"),
            new Person("Isabella", "Johnson", "isabella.johnson@example.com", "455-777-645"),
            new Person("Ethan", "Williams", "ethan.williams@example.com", "888-504-254"),
            new Person("Emma", "Jones", "emma.jones@example.com", "123-548-350"),
            new Person("Michael", "Brown", "michael.brown@example.com", "650-120-600"));

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(550);
        stage.setHeight(500);

        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));

        table.setEditable(true);

        TableColumn firstNameCol = new TableColumn("First Name");
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));

        TableColumn lastNameCol = new TableColumn("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));

        TableColumn emailCol = new TableColumn("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));

        TableColumn phoneCol = new TableColumn("Phone");
        phoneCol.setMinWidth(100);
        phoneCol.setCellValueFactory(new PropertyValueFactory<Person, String>("phone"));

        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol, phoneCol);

        table.skinProperty().addListener((obs, oldSkin, newSkin) -> {
            final TableHeaderRow header = (TableHeaderRow) table.lookup("TableHeaderRow");
            header.reorderingProperty().addListener((o, oldVal, newVal) -> {
                ObservableList columns = table.getColumns();

                // If the first columns is not in the first index change it
                if (columns.indexOf(firstNameCol) != 0) {
                    columns.remove(firstNameCol);
                    columns.add(0, firstNameCol);
                }
                // Use the same logic for the last column
                if (columns.indexOf(phoneCol) != columns.size() - 1) {
                    columns.remove(phoneCol);
                    columns.add(columns.size(), phoneCol);
                }
            });
        });

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table);

        ((Group) scene.getRoot()).getChildren().addAll(vbox);

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

    public static class Person {

        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;
        private final SimpleStringProperty phone;

        private Person(String fName, String lName, String email, String phone) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
            this.phone = new SimpleStringProperty(phone);
        }

        public String getPhone() {
            return phone.get();
        }

        public String getFirstName() {
            return firstName.get();
        }

        public String getLastName() {
            return lastName.get();
        }

        public String getEmail() {
            return email.get();
        }

    }
}

You could also add the firstNameCol.impl_setReorderable(false); and phoneCol.impl_setReorderable(false); to prevent the dragging of the first and last columns as well.

JKostikiadis
  • 2,847
  • 2
  • 22
  • 34
  • Yes this is working, but I thought there is a way to prevent even that move which would change place if you let it. The best solution would be for me to prevent dragging to the first/last column if it is possible, if it not, i go this way. – Sunflame Oct 23 '17 at 14:25
  • @Sunflame you could use the `impl_setReorderable(false);` to the columns you don't want to be able to be dragged but I don't believe there is a way (at least an easy way) to prevent the visual of other columns to be dragged over the non-draggable columns, even if the rearrange of the columns is not taking place. – JKostikiadis Oct 23 '17 at 14:33
  • Yeah you are probably right, but, I used the part with the check if the first was moved, then I put it back to its right place. Not the most elegant solution but it works. Thanks for suggestion this way of solution. – Sunflame Oct 23 '17 at 15:30