0

I have a view, in that view a few tableViews, but lets say I have two tables. When I reorder the columns in the first table(by using drag and drop) I want to do the same thing in the second table. I was trying in a way but I get IllegalStateException: Duplicate TreeTableColumns detected in TreeTableView columns list with titles ''

This is that I have tried:

    private void handleDragAndDrop() {
        firstTable.getColumns().addListener((ListChangeListener<? super TableColumn<?, ?>>) c -> {
            while (c.next()) {
                List<String> addedIDs = c.getAddedSubList()
                        .stream()
                        .map(TableColumn::getId)
                        .collect(Collectors.toList());
                Map<String, String> changedIds = getChangedIds(addedIDs);
                changedIds.entrySet()
                        .stream()
                        .reduce((firstEntry, lastEntry) -> lastEntry)
                        .ifPresent(entry-> reorderTheSecondTable(secondTable.getColumns(),entry.getValue(),
                                entry.getKey()));
            }
        });
    }

    private Map<String, String> getChangedIds(List<String> iDs) {
        return new LinkedHashMap<>(iDs.stream()
                .skip(1) // I don't need the first column, that will be never reordered.
                .filter(id -> !id.equals(String.valueOf(iDs.indexOf(id)))) // I need only the changed id-index pairs.
                .collect(Collectors.toMap(i -> String.valueOf(iDs.indexOf(i)), Function.identity())));
    }

    private void reorderTheSecondTable(ObservableList<? extends TableColumnBase<?, ?>> list, String start, String end) {
        Collections.rotate(list.subList(Integer.valueOf(start), Integer.valueOf(end) + 1), 1);
    }

The columns have ids from 1 to table.getColumns().size()-1 (0 is the immutable column)

The exception is thrown at line Collections.rotate(...

I don't know if is this the correct way to do, but I didn't find any better solution and even this is not a solution since is not working.

4
  • Do both the TableViews map the same object? Commented Sep 4, 2017 at 13:51
  • No the first table has TableView<FirstTablesData> firstTable, and the second table is a TreeTableView<SecondTableData> secondTable Commented Sep 4, 2017 at 13:55
  • Is there the same amount of columns in both TableViews? Commented Sep 4, 2017 at 13:58
  • Yes the amount of columns are the same all time, or more precisely at the same time each table has the same amount of columns. Commented Sep 4, 2017 at 14:00

1 Answer 1

1

You can do something like this:

TableView<FirstTablesData> firstTable = new TableView<>();

// create a list that holds the original order of the columns:
List<TableColumn<FirstTablesData, ?>> firstTableOriginalColumns = new ArrayList<>(...);

firstTable.getColumns().setAll(firstTableOriginalColumns);

// same for second table:

TableView<SecondTablesData> secondTable = new TableView<>();
List<TableColumn<SecondTablesData, ?>> secondTableOriginalColumns = new ArrayList<>(...);
secondTable.getColumns().setAll(secondTableOriginalColumns);

firstTable.getColumns().addListener((Change<? extends TableColumn<FirstTablesData,?>> change) -> 
    secondTable.getColumns().setAll(firstTable.getColumns().stream()
        .mapToInt(firstTableOriginalColumns::indexOf)
        .mapToObj(secondTableOriginalColumns::get)
        .collect(Collectors.toList())));

This creates lists that "remember" the original ordering of the columns in each table. The listener just looks up the index in the original list of columns for the first table, and creates a list corresponding to that ordering for the second table's columns. This code assumes both tables have the same number of columns.

Here is a SSCCE:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import javafx.application.Application;
import javafx.collections.ListChangeListener.Change;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class CoordinatedTableColumns extends Application {

    @Override
    public void start(Stage primaryStage) {
        TableView<Object> firstTable = new TableView<>();
        List<TableColumn<Object, ?>> firstTableOriginalColumns = Arrays.asList(
                new TableColumn<>("Column 1"),
                new TableColumn<>("Column 2")
        );
        firstTable.getColumns().setAll(firstTableOriginalColumns);

        TableView<String> secondTable = new TableView<>();
        List<TableColumn<String, ?>> secondTableOriginalColumns = Arrays.asList(
                new TableColumn<>("Column A"),
                new TableColumn<>("Column B")
        );
        secondTable.getColumns().setAll(secondTableOriginalColumns);

        firstTable.getColumns().addListener((Change<? extends TableColumn<Object,?>> change) -> 
        secondTable.getColumns().setAll(firstTable.getColumns().stream()
            .mapToInt(firstTableOriginalColumns::indexOf)
            .mapToObj(secondTableOriginalColumns::get)
            .collect(Collectors.toList())));

        HBox root = new HBox(5, firstTable, secondTable);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Sign up to request clarification or add additional context in comments.

7 Comments

It is working perfectly as expected, thank you very much.
I am wondering if it can be optimized by removing just the modified columns and add them all in the right order...Because if I have 30(or more) columns with data and I just swap in 2 columns which are next to each other, then I removed 28 and added 28 unnecessary, am I right?
@Sunflame But why would you care about that? The code to minimize the changes would be really complex and hard to maintain.
I was just thinking about if I can reduce the unnecessary operations, because is there a case to have up to 50 columns, and 5 tables in a view, so if I reorder just 2 of them there is a lot of work in the background.
@Sunflame Again, why do you care? Have you established that there's a performance problem? If not, you should strive to write the simplest and most maintainable code you can.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.