I wrote a custom TableRowSorter
that changes the sort order when you click on a JTableHeader
fromSortOrder.UNSORTED
=> SortOrder.ASCENDING
=> SortOrder.DESCENDING
=> SortOrder.ASCENDING
=> SortOrder.DESCENDING
=> ...
toSortOrder.UNSORTED
=> SortOrder.ASCENDING
=> SortOrder.DESCENDING
=>SortOrder.UNSORTED
=> SortOrder.ASCENDING
=> SortOrder.DESCENDING
=> ...
ADU_SortOrder.java
package order;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SortOrder;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class ADU_SortOrder<M extends TableModel> extends TableRowSorter<M> {
public ADU_SortOrder(M model) {
setModel(model);
}
boolean firstTime = true; //Needed in case there are any initial sort keys
int columnHolder = -1;
@Override
public void toggleSortOrder(int column) {
List<? extends SortKey> sortKeys = getSortKeys();
if(sortKeys.size() == 0) { //For if there are no initial sort keys
List<SortKey> keys = new ArrayList<SortKey>();
keys.add(new SortKey(column, SortOrder.ASCENDING));
setSortKeys(keys);
return;
}
if (sortKeys.size() > 0 && columnHolder == column || firstTime) {
if(firstTime) {
firstTime = false;
columnHolder = column;
if(column != sortKeys.get(0).getColumn()) {
List<SortKey> keys = new ArrayList<SortKey>(getSortKeys());
keys.set(0, new SortKey(column, SortOrder.ASCENDING));
setSortKeys(keys);
return;
}
}
List<SortKey> keys = new ArrayList<SortKey>(getSortKeys());
keys.set(0, new SortKey(column, setNextOrder(sortKeys.get(0).getSortOrder())));
setSortKeys(keys);
return;
} else if(sortKeys.size() > 0 && columnHolder != column && !firstTime) {
List<SortKey> keys = new ArrayList<SortKey>(getSortKeys());
keys.set(0, new SortKey(column, SortOrder.ASCENDING));
setSortKeys(keys);
columnHolder = column;
return;
}
super.toggleSortOrder(column);
}
private SortOrder setNextOrder(SortOrder order) {
switch (order) {
case ASCENDING:
return SortOrder.DESCENDING;
case DESCENDING:
return SortOrder.UNSORTED;
case UNSORTED:
return SortOrder.ASCENDING;
default:
return SortOrder.UNSORTED;
}
}
}
And it works really well when you implement into something like this
JTableTest.java - Working example
import java.awt.GridLayout;
import java.util.List;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableModel;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import order.ADU_SortOrder;
@SuppressWarnings("serial")
public class JTableTest extends JFrame {
private JTableTest() {
super("JTable Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1, 1));
createPanel();
pack();
setVisible(true);
}
JPanel panel = new JPanel(new GridLayout(1, 1));
JScrollPane scroll;
private void createPanel() {
Object[] headers = {"Select", "Title", "Artist", "Length", "Title"};
Object[][] sampleData = {{true, "Bat Outta Hell", "Meat Loaf", "673", "Bat Outta Hell"},
{false, "Spanish Train", "Chris De Burgh", "358", "Spanish Train"},
{true, "Bat Outta Hell", "Meat Loaf", "673", "Bat Outta Hell"}};
JTable table = new JTable(sampleData, headers);
//Sort Order Part
ADU_SortOrder<TableModel> sortOrder = new ADU_SortOrder<TableModel>(table.getModel());
List<RowSorter.SortKey> sortKeys = new ArrayList<>();
sortKeys.add(new RowSorter.SortKey(0, SortOrder.ASCENDING));
sortOrder.setSortKeys(sortKeys);
table.setRowSorter(sortOrder);
scroll = new JScrollPane(table);
panel.add(scroll);
getContentPane().add(panel);
}
public static void main(String[] args) {
new JTableTest();
}
}
However, as soon as you add a custom BasicTableHeaderUI
such as the example one below.
CustomHeaderUI.java
package ui;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.TableColumnModel;
@SuppressWarnings("serial")
public class CustomHeaderUI extends BasicTableHeaderUI {
public void canReorder(String col, boolean reorder) {
TableColumnModel cM = header.getColumnModel();
for(int i = 0; i < cM.getColumnCount(); i++) {
if(header.getTable().getColumnName(i).equals(col)) {
canReorder(i, reorder);
break;
}
}
}
public void canReorder(String col, int instance, boolean reorder) {
TableColumnModel cM = header.getColumnModel();
int column = -1;
for(int i = 0; i < cM.getColumnCount(); i++) {
if(header.getTable().getColumnName(i).equals(col)) {
column++;
if(column == instance - 1) {
canReorder(i, reorder);
break;
}
}
}
}
public void canReorderAll(String col, boolean reorder) {
TableColumnModel cM = header.getColumnModel();
for(int i = 0; i < cM.getColumnCount(); i++) {
if(header.getTable().getColumnName(i).equals(col))
canReorder(i, reorder);
}
}
public void canReorder(int col, boolean reorder) {
}
}
JTableTest.java - SSSCE/MCVE
import java.awt.GridLayout;
import java.util.List;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.RowSorter.SortKey;
import javax.swing.SortOrder;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableModel;
import order.ADU_SortOrder;
import ui.CustomHeaderUI;
@SuppressWarnings("serial")
public class JTableTest extends JFrame {
private JTableTest() {
super("JTable Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1, 1));
createPanel();
pack();
setVisible(true);
}
JPanel panel = new JPanel(new GridLayout(1, 1));
JScrollPane scroll;
private void createPanel() {
Object[] headers = {"Select", "Title", "Artist", "Length", "Title"};
Object[][] sampleData = {{true, "Bat Outta Hell", "Meat Loaf", "673", "Bat Outta Hell"},
{false, "Spanish Train", "Chris De Burgh", "358", "Spanish Train"},
{true, "Bat Outta Hell", "Meat Loaf", "673", "Bat Outta Hell"}};
JTable table = new JTable(sampleData, headers);
ADU_SortOrder<TableModel> sortOrder = new ADU_SortOrder<TableModel>(table.getModel());
List<SortKey> keys = new ArrayList<SortKey>();
keys.add(new RowSorter.SortKey( 0, SortOrder.ASCENDING));
sortOrder.setSortKeys(keys);
table.setRowSorter(sortOrder);
//Adds Custom UI
CustomHeaderUI headerUI = new CustomHeaderUI();
headerUI.installUI(table.getTableHeader());
headerUI.canReorder("Title", true);
headerUI.canReorder("Title", 1, true);
headerUI.canReorderAll("Title", true);
headerUI.canReorder(3, true);
scroll = new JScrollPane(table);
panel.add(scroll);
getContentPane().add(panel);
}
public static void main(String[] args) {
new JTableTest();
}
}
That includes some sample CustomHeaderUI
methods shows clearly the two problems. Firsly the sort order is incorrect. If you start on the first column, Column 0
, the sortorder is
SortOrder.ASCENDING
=> SortOrder.UNSORTED
=> SortOrder.DESCENDING
=> SortOrder.ASCENDING
=> SortOrder.UNSORTED
=> SortOrder.DESCENDING
=> ...
Starts ascending because of the keys.add(new RowSorter.SortKey( 0, SortOrder.ASCENDING));
not becasue of a glitch with my code
This is not the desired sort order described at the start. The second problem is that when you drag the columns in the MCVE it jumps two columns instead of one column. I would really appreciate help with fixing these problems.