Hi folks! I'm trying to develop a JTable that automatically changes the row order when the user drags a column to a new location. The code below generates a 5X5 multiplication table. When the user begins to drag a column, the column model listener sets a boolean to true to indicate that a drag is taking place. When the user releases the mouse, the mouse listener for the table header registers the release, and if a drag was taking place, the table data is supposed to update to accomodate the new column order. I'd like to keep the rows in the same order as the columns so that the diagonal of the table is a diagonal of square numbers. When I drag a column, the rows do change their order to reflect the new column order, but when the table repopulates the data for display, it treats the columns as if they were in the same order that they were in before the drag occurred. I think the problem is related to the JTable's getValueAt function that specifies the column order as the view order, and not the table model order. It seems like this has something to do with the convertColumnIndexToModel(int viewColumnIndex) JTable method. Thanks for any help you can give!
I've developed a small, runnable example of the behavior I'm seeing. After you run it and it shows the table, try dragging a column to a new location. You'll see the rows change order, but the multiplication results for the columns that just changed positions are wrong for the rows that changed position.
Here is my code:
import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Vector; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.table.AbstractTableModel; @SuppressWarnings("serial") public class ExpTable extends JPanel { private JTable table; boolean columnDragging; boolean viewStable; public ExpTable() { super(new GridLayout(1,0)); final ExpTableModel myModel = new ExpTableModel(); table = new JTable(myModel); columnDragging = false; viewStable = false; table.getTableHeader().addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { if(columnDragging) { System.out.println("Drag Completed"); Vector<Integer> newColumns = new Vector<Integer>(); for(int i = 1; i < table.getColumnCount(); i++) { newColumns.add(new Integer(table.getColumnName(i))); } for(int i = 1; i < table.getColumnCount(); i++) { table.getColumnModel().getColumn(i).setHeaderValue(newColumns.get(i - 1)); } myModel.repopulateTable(newColumns); table.setModel(myModel); PrintColumnNames(); myModel.PrintTableData(); } } }); table.getColumnModel().addColumnModelListener(new TableColumnModelListener() { @Override public void columnAdded(TableColumnModelEvent e) {} @Override public void columnRemoved(TableColumnModelEvent e) {} @Override public void columnMoved(TableColumnModelEvent e) { columnDragging = true; } @Override public void columnMarginChanged(ChangeEvent e) {} @Override public void columnSelectionChanged(ListSelectionEvent e) {} }); table.setPreferredScrollableViewportSize(new Dimension(500,300)); table.setFillsViewportHeight(true); JScrollPane scrollPane = new JScrollPane(table); add(scrollPane); } private static void createAndShowGUI() { JFrame frame = new JFrame("Table Experiment"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); ExpTable newTable = new ExpTable(); newTable.setOpaque(true); frame.setContentPane(newTable); frame.pack(); frame.setVisible(true); } public void PrintColumnNames() { System.out.print("Column Names: "); for(int i = 0; i < table.getColumnCount(); i++) { String buf = table.getColumnName(i) + " "; System.out.print(buf); } System.out.println(); System.out.print("Table Data Model Column Names: "); for(int i = 0; i < table.getColumnCount(); i++) { String buf = table.getModel().getColumnName(i) + " "; System.out.print(buf); } System.out.println(); System.out.print("Table Column Model Column Names: "); for(int i = 0; i < table.getColumnModel().getColumnCount(); i++) { System.out.print(table.getColumnModel().getColumn(i).getHeaderValue() + " "); } System.out.println(); } public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } } @SuppressWarnings("serial") class ExpTableModel extends AbstractTableModel { private Vector<Integer> columnNames; private Vector<Vector<Integer>> rowHolder; private int squareSize = 5; public ExpTableModel() { columnNames = new Vector<Integer>(); rowHolder = new Vector<Vector<Integer>>(); for(int i = 1; i <= squareSize; i++) { columnNames.add(new Integer(i)); } columnNames.add(0, new Integer(0)); for(int i = 1; i < columnNames.size(); i++) { Vector<Integer> rowData = new Vector<Integer>(); rowData.add(0, columnNames.get(i)); for(int j = 1; j <= squareSize; j++) { rowData.add(columnNames.get(i)*columnNames.get(j)); } rowHolder.add(rowData); } } @Override public int getRowCount() { return rowHolder.size(); } @Override public int getColumnCount() { return columnNames.size(); } @Override public String getColumnName(int column) { return columnNames.get(column).toString(); } @Override public Integer getValueAt(int rowIndex, int columnIndex) { Vector<Integer> row = rowHolder.elementAt(rowIndex); return row.elementAt(columnIndex); } public void repopulateTable(Vector<Integer> newColumnNames) { columnNames.removeAllElements(); columnNames = new Vector<Integer>(newColumnNames); columnNames.add(0, new Integer(0)); rowHolder.removeAllElements(); for(int i = 1; i < columnNames.size(); i++) { Vector<Integer> rowData = new Vector<Integer>(); rowData.add(0, columnNames.get(i)); for(int j = 1; j <= squareSize; j++) { rowData.add(columnNames.get(i)*columnNames.get(j)); } rowHolder.add(rowData); } } public void PrintTableData() { for(int i = 0; i < getRowCount(); i++) { System.out.print("Row " + i + ": "); for(int j = 0; j < rowHolder.get(i).size(); j++) { System.out.print(rowHolder.get(i).get(j) + " "); } System.out.println(); } } }