You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TableView列顺序变更时change.wasPermutated()始终返回false如何解决?

解决JavaFX两个TableView列顺序同步问题

问题原因

JavaFX中拖动TableView列调整顺序时,内部并非通过列表排列(permutation)实现,而是先移除目标列,再将其插入到新位置。因此ListChangeListener的change.wasPermutated()始终返回false,触发的是remove和add类型的变更事件。

解决方案

我们可以直接监听第一个表格的列列表变更,根据其列的顺序,重新排列第二个表格的对应列。由于两个表格的列是独立实例,可通过列标题(或自定义标识)匹配对应列,再同步顺序。

修改后的完整代码

import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

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

public class JavaFxTest7 extends Application {

    private static class Student {
        private int id;
        private String name;
        private int mark;

        public Student(int id, String name, int mark) {
            this.id = id;
            this.name = name;
            this.mark = mark;
        }

        public int getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        public int getMark() {
            return mark;
        }
    }

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

    @Override
    public void start(Stage stage) {
        var table1 = createTable();
        var table2 = createTable();

        // 监听table1的列顺序变更,同步到table2
        table1.getColumns().addListener((ListChangeListener<? super TableColumn<Student, ?>>) change -> {
            // 获取table1当前的列标题顺序
            List<String> columnOrder = table1.getColumns().stream()
                    .map(TableColumn::getText)
                    .collect(Collectors.toList());

            // 按照该顺序重新排列table2的列
            List<TableColumn<Student, ?>> newColumnList = new ArrayList<>();
            for (String colTitle : columnOrder) {
                for (TableColumn<Student, ?> col : table2.getColumns()) {
                    if (col.getText().equals(colTitle)) {
                        newColumnList.add(col);
                        break;
                    }
                }
            }
            // 更新table2的列顺序
            table2.getColumns().setAll(newColumnList);
        });

        var scene = new Scene(new VBox(table1, table2), 300, 300);
        stage.setScene(scene);
        stage.show();
    }

    private TableView<Student> createTable() {
        var table = new TableView<>(FXCollections.observableList(Arrays.asList(
                new Student(1, "Billy", 3),
                new Student(2, "Johnny", 4),
                new Student(3, "Mickey", 5)
        )));

        var idColumn = new TableColumn<Student, Integer>("ID");
        idColumn.setCellValueFactory(data -> new ReadOnlyObjectWrapper<>(data.getValue().getId()));

        var nameColumn = new TableColumn<Student, String>("Name");
        nameColumn.setCellValueFactory(data -> new ReadOnlyStringWrapper(data.getValue().getName()));

        var markColumn = new TableColumn<Student, Integer>("Mark");
        markColumn.setCellValueFactory(data -> new ReadOnlyObjectWrapper<>(data.getValue().getMark()));

        table.getColumns().addAll(idColumn, nameColumn, markColumn);
        table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN);
        return table;
    }
}

代码说明

  1. 监听table1.getColumns()的变更事件,每次变更时获取table1当前的列标题顺序。
  2. 根据标题匹配table2中的对应列,生成新的列顺序列表。
  3. 通过table2.getColumns().setAll(newColumnList)更新table2的列顺序,确保与table1完全一致。

这种方式无需区分具体的变更类型(remove/add/permutate),无论通过何种方式修改table1的列顺序,都能可靠同步到table2。

内容的提问来源于stack exchange,提问作者user5182503

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 09:46:36