拖动后如何将 JTable 列排序到原始位置

How to order JTable columns to original position after being draged

我有一个 JTable,我想让用户可以根据自己的需要来定位列,以获得自定义的信息视图。但与此同时,我需要一个函数(或算法)来在特定事件发生时将这些列设置到它的原始位置。

我知道当你想访问单元格中的数据时,无论用户将其设置在什么位置,该列的索引都将保持不变。

例如:一个包含 3 列的 JTable,假设为 column1、column2、column3。如果用户拖动它们以显示为 column2、column3、column1,则 column1 仍将具有 0 索引。所以必须有一种方法可以轻松地将它们重新排序回原来的位置。我知道要访问列的重新排序,您需要获取 header.

JTableHeader header = table.getTableHeader();
header.setReorderingAllowed(true);

所以从那里我查看了 JTableHeader 的文档 class 但我没有找到任何有用的东西,也没有通过搜索特定的解决方案。我希望我已经正确解释了这个问题。这是我的代码的一个类似示例。

DefaultTableModel model = new DefaultTableModel();
table = new JTable(model);
model.addColumn(column1);
model.addColumn(column2);
model.addColumn(column3);
JTableHeader header = table.getTableHeader();
header.setReorderingAllowed(true);


JButton button = new JButton("Reorder");
button.addActionListener(new ActionListener){
    @Override
    public void actionPerformed(ActionEvent e) {
     //the code that orders the columns to its original position         
   }
};

我还知道默认情况下列的重新排序设置为 true,但我添加它是为了清楚地说明并知道我还可以从那里添加或执行什么。

编辑 1 第一个解决方案,在名为 HelperArrays 的自定义 class 中使用 private static int[] ColumnsWidth 数组,并根据需要使用列宽,其中 getter 方法 returns int 用于每列的宽度,将数组的索引设置为参数。我们可以从 JTable Object 重置 DefaultTableModel,但还需要重置列的宽度,以便成功地将列重新排序到它们的原始位置

  private static int[] columnsWidhth = {widht1, widhth2, width3};

  public static int getColumnsWidth(int index){
  returns ColumnsWidth[index];
  }

  @Override
  public void actionPerformed(ActionEvent e) {
      table.setModel(new DefaultTableModel());
      table.setModel(model);
      DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
      centerRenderer.setHorizontalAlignment(JLabel.CENTER);
      for (int i = 0; i < table.getColumnCount(); i++) {
          table.getColumnModel().getColumn(i).setMinWidth(HelperArrays.getColumnsWidth(i));
          table.getColumnModel().getColumn(i).setMaxWidth(HelperArrays.getColumnsWidth(i));
          table.getColumnModel().getColumn(i).setPreferredWidth(HelperArrays.getColumnsWidth(i));      
      }
  }

编辑 2 第二个也是最后一个解决方案,直接使用 TableColumnModel Object 中的 moveColumn() 函数对列重新排序,使用循环按其原始索引恢复它们。

@Override
public void actionPerformed(ActionEvent e) {
    TableModel model = table.getModel();
    TableColumnModel tcm = table.getColumnModel();
    for (int i = 0; i < model.getColumnCount() - 1; i++) {
            int location = tcm.getColumnIndex(model.getColumnName(i));
            tcm.moveColumn(location, i);
   }

}

我不知道是否有更好的解决方案,但这似乎有效:

TableModel model = table.getModel();
table.setModel(new DefaultTableModel());
table.setModel(model);

完整示例:

public class TableColumnOrderTest {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            DefaultTableModel dm = new DefaultTableModel();
            dm.addColumn("Column 1");
            dm.addColumn("Column 2");
            dm.addColumn("Column 3");
            dm.addColumn("Column 4");

            Object[][] data = { 
                    { "1", "Something","hello","World" }, { "102", "Something Else" }, 
                    { "55", "Something","dfsdf","fsdafas" }, { "66", "Something" },
                    { "1000", "Something" }, { "1524", "Something" }, 
                    { "5801", "Something" }, { "-55", "Something" },};

            for (Object[] row : data) {
                dm.addRow(row);
            }
            JTable table = new JTable(dm);

            JPanel panel = new JPanel(new BorderLayout());
            panel.add(new JScrollPane(table));

            JButton button = new JButton("button");
            button.addActionListener(e -> {
                table.setModel(new DefaultTableModel());
                table.setModel(dm);
            });

            panel.add(button, BorderLayout.PAGE_END);
            JOptionPane.showMessageDialog(null, panel);
        });
    }
}

预览:

编辑

最近问了。删除和 re-adding 模型将重击 table 的渲染器。如果你使用自定义 TableCellRenderers 并且你想在 re-setting 模型之后保留它们,你可以使用类似下面的东西:

private static void restoreColumnOrdering(JTable table) {
    TableModel model = table.getModel();
    Map<Object, TableCellRenderer> renderers = new HashMap<>();
    Map<Object, Integer> widths = new HashMap<>();

    for (int i = 0; i < table.getColumnCount(); i++) {
        TableColumn column = table.getColumnModel().getColumn(i);
        TableCellRenderer cellRenderer = column.getCellRenderer();
        renderers.put(column.getIdentifier(), cellRenderer);
        widths.put(column.getIdentifier(), column.getPreferredWidth());
    }

    table.setModel(new DefaultTableModel());
    table.setModel(model);

    // Reset renderers
    for (int i = 0; i < table.getColumnCount(); i++) {
        TableColumn column = table.getColumnModel().getColumn(i);
        TableCellRenderer cellRenderer = renderers.get(column.getIdentifier());
        column.setCellRenderer(cellRenderer);
        column.setPreferredWidth(widths.get(column.getIdentifier()));
    }
}

So from there I looked at the documentation of JTableHeader

有关 TableColumn 如何显示的信息包含在 TableColumnModel 中。

您可以只使用 moveColumn(...) 方法恢复列顺序。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

public class TableColumnRestore2 extends JFrame
{
    public TableColumnRestore2()
    {
        final JTable table = new JTable(5, 8);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane= new JScrollPane( table );
        getContentPane().add(scrollPane);

        JButton restore = new JButton("Restore Columns");
        getContentPane().add(restore, BorderLayout.SOUTH);
        restore.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                TableModel model = table.getModel();
                TableColumnModel tcm = table.getColumnModel();

                for (int i = 0; i < model.getColumnCount() - 1; i++)
                {
                    int location = tcm.getColumnIndex( model.getColumnName(i) );
                    tcm.moveColumn(location, i);
                }
            }
        });
    }

    public static void main(String[] args)
    {
        TableColumnRestore2 frame = new TableColumnRestore2();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}