I have made a TableRowSorter
which should update the cycle in which each column is sorted from ASCENDING => DESCENDING => ASCENDING => DESCENDING => ...
to ASCENDING => DESCENDING => UNSORTED => ASCENDING => DESCENDING => UNSORTED => ...
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);
}
@Override
public void toggleSortOrder(int column) {
List<? extends SortKey> sortKeys = getSortKeys();
if (sortKeys.size() > 0) {
List<SortKey> keys = new ArrayList<SortKey>(getSortKeys());
keys.set(0, new SortKey(column, setNextOrder(sortKeys.get(0).getSortOrder())));
setSortKeys(keys);
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;
}
}
}
In the given example I will try to describe what I expect to happen and what actually happens. You have a JTable
with two columns. The SortKeys
which are used at the start make it so that the last sort in each column were so that the columns were SortOrder.ASCENDING
What I expect would happen here would be the following.
Sort Order in: Column 1 Column 2
Start: ASCENDING ASCENDING
Click C1: DESCENDING ASCENDING
Click C1: UNSORTED ASCENDING
Click C2: UNSORTED DESCENDING
Click C1: ASCENDING DESCENDING
Click C2: ASCENDING UNSORTED
What actually happens:
Sort Order in: Column 1 Column 2
Start: ASCENDING ASCENDING
Click C1: DESCENDING ASCENDING
Click C1: UNSORTED ASCENDING
Click C2: UNSORTED ASCENDING
Click C1: DESCENDING ASCENDING
Click C2: DESCENDING UNSORTED
As you can see instead of getting the sort order of the column clicked, the TableRowSorter
gets the last sort order applied and then just applies the next sort order to the next column clicked. How would I be able to treat each column individually and update the columns so that it worked as expected?
Here is a MCV. I apologise for not including one previously.
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SortOrder;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter.SortKey;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
public class MVC extends JFrame {
private static final long serialVersionUID = -8809862571237032846L;
private MVC() {
setTitle("MVC");
createAndRunGUI();
pack();
setVisible(true);
setLocationRelativeTo(null);
}
private void createAndRunGUI() {
setLayout(new GridLayout(1, 1));
String[] tableHeaders = {"Col 1", "Col 2"};
String[][] tableData = {
{"Hi", "Animals"},
{"Bob", "Of"},
{"Phil", "The"},
{"Dog", "World"},
{"Cat", "Include"},
{"Pill", "Fish"},
{"Dab", "Ants"},
{"Bob", "Hippos"},
{"Fill", "Humans"},
{"Space", "TVs"},
{"Up", "Is"},
{"Now", "That"},
{"Even", "Right"},
{"More", "Person"},
{"Data", "?"}
};
JTable table = new JTable(tableData, tableHeaders);
table.setAutoCreateRowSorter(true);
ADU_SortOrder<TableModel> tableSorter = new ADU_SortOrder<TableModel>(table.getModel());
List<SortKey> keys = new ArrayList<SortKey>();
//keys.add(new RowSorter.SortKey( 0, SortOrder.ASCENDING));
//keys.add(new RowSorter.SortKey( 1, SortOrder.ASCENDING));
tableSorter.setSortKeys(keys);
table.setRowSorter(tableSorter);
JScrollPane myScrollTable = new JScrollPane(table);
myScrollTable.setPreferredSize(new Dimension(600, 600));
JPanel cont = new JPanel();
cont.add(myScrollTable);
getContentPane().add(cont);
}
public static void main(String[] args) {
new MVC();
}
private class ADU_SortOrder<M extends TableModel> extends TableRowSorter<M> {
public ADU_SortOrder(M model) {
setModel(model);
}
@Override
public void toggleSortOrder(int column) {
List<? extends SortKey> sortKeys = getSortKeys();
if (sortKeys.size() > 0) {
List<SortKey> keys = new ArrayList<SortKey>(getSortKeys());
keys.set(0, new SortKey(column, setNextOrder(sortKeys.get(0).getSortOrder())));
setSortKeys(keys);
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;
}
}
}
}
Edit 2
Looking at the specific method toggleSortOrder
whilst the program is running it becomes apparent that the problem is with the part of code which says setNextOrder(keys.get(0).getSortOrder())
. This is because when the code returns getSortKeys()
as an ArrayList
the size of the list is only ever 0
or 1
. This means that when the length of the list is 1
the code get(0)
returns the last column sorted but the code get(column)
would cause an IndexOutOfBoundsException
. So how can I allow the program to get the SortKeys
for every column?
@Override
public void toggleSortOrder(int column) {
System.out.println("Column: " + column);
List<SortKey> keys = new ArrayList<SortKey>(getSortKeys());
System.out.println("List Size: " + keys.size());
if (keys.size() > 0) {
keys.set(0, new SortKey(column, setNextOrder(keys.get(0).getSortOrder())));
setSortKeys(keys);
return;
}
super.toggleSortOrder(column);
}
Edit 3
Using Andreas' suggestion I created a way to be able to use keys.set(column, new SortKey(column, setNextOrder(keys.get(column).getSortOrder())));
List<SortKey> keys = new ArrayList<SortKey>();
@Override
public void toggleSortOrder(int column) {
System.out.println("Column: " + column);
System.out.println("List Size: " + keys.size());
if (keys.size() > 0) {
keys.set(column, new SortKey(column, setNextOrder(keys.get(column).getSortOrder())));
setSortKeys(keys);
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;
}
}
private void initialSortOrder(M model) {
for(int i = 0; i < model.getColumnCount(); i++) {
keys.add(new RowSorter.SortKey( i, SortOrder.ASCENDING));
}
}
However using this method column 1 can be sorted but only the words Of
and Hippo
can be sorted in the second column. I know this has turned into a very long question and sorry but I do appreciate any help
In order to fix this, I needed to add a few more if statements and one or two variables.
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;
}
}
}