Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Maybe this is a way to do it. There's probably a more elegant way to do it around.</p> <p>The DefaultRowSorter Comparator only compares values for one column at a time, without additional information it alone can not make sure that one column in the set of columns (say column 1) must always be the first column to sort by.</p> <p>If you mess with DefaultRowSorter.toggleSortOrder and add a new SortKey to keys at position 0 before setSortKeys gets called (this would be the primary column you always want to sort by first [column 1]), the ascending and descending arrows displayed in the column headers constantly mark column 1 (rightfully so), but this is not what the user expects if she clicks on column 2.</p> <p>Another approach is to have Comparator know about column sort relationships. An easy way is to add information about sort precedences to the Objects for Comparator.compare. Simple precedences can be represented by a prefix String (for example: prefix "a" for column 1 and prefix "b" for all other columns). </p> <p>PrefixedData can contain String, Boolean, Timestamp or null values and a prefix:</p> <pre><code>public class PrefixedData { private String sData=null, prefix=""; private Timestamp tData=null; private Boolean bData=null; public void setData(String data) { sData=data; } public void setData(Timestamp data) { tData=data; } public void setData(boolean data) { bData=data; } public void setPrefix(String prefix) { this.prefix=prefix; } public String getPrefix() { return prefix; } public Object getData() { if(sData!=null) return sData; if(tData!=null) return tData; if(bData!=null) return bData; return null; } } </code></pre> <p>JTable cells can be rendered like this for String, Boolean and Timestamp, if your table model returns PrefixedData for DefaultTableModel.getValueAt:</p> <pre><code>private static class PrefixedDataRenderer3 extends JLabel implements TableCellRenderer { private static final SimpleDateFormat formatter = new SimpleDateFormat("MM.yyyy HH:mm:ss"); private static final JCheckBox box = new JCheckBox(); public PrefixedDataRenderer() { setOpaque(true); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { remove(box); PrefixedData p=(PrefixedData) value; if(p.getData()==null) return this; if(p.getData().getClass().equals(String.class)) { setText((String)p.getData()); return this; } if(p.getData().getClass().equals(Timestamp.class)) { setText(formatter.format((Timestamp)p.getData())); return this; } if(p.getData().getClass().equals(Boolean.class)) { box.setSelected(((Boolean)p.getData()).booleanValue()); add(box); } return this; } } </code></pre> <p>And finally the Comparator can decide the order of things:</p> <pre><code>Comparator&lt;Object&gt; PrefixedDataComparator = new Comparator&lt;Object&gt;() { private List&lt;? extends SortKey&gt; sortKeys; @Override public int compare(Object o1, Object o2) { PrefixedData p1=(PrefixedData) o1; PrefixedData p2=(PrefixedData) o2; //First: compare prefixes (precedence data) int prefixResult=p1.getPrefix().compareTo(p2.getPrefix()); sortKeys = tableOU.getRowSorter().getSortKeys(); //The prefixes are not the same, so return the result of the prefix comparision //The result has to be inverted if we're sorting in descending order //for the column the user has clicked if(prefixResult!=0) return (sortKeys.get(0).getSortOrder().equals(SortOrder.ASCENDING) ? prefixResult : -prefixResult ); //Only if the prefixes are the same do we have to compare the payload data //Try to impose an order for null if(p1.getData()==null &amp;&amp; p2.getData()!=null) return -1; if(p1.getData()==null &amp;&amp; p2.getData()==null) return 0; if(p1.getData()!=null &amp;&amp; p2.getData()==null) return 1; //Objects compared are identical if(p1.getData().equals(p2.getData())) return 0; //Compare String if(p1.getData().getClass().equals(String.class)) { String s1=(String) p1.getData(); String s2=(String) p2.getData(); return s1.toLowerCase().compareTo(s2.toLowerCase()); } //Compare Timestamp if(p1.getData().getClass().equals(Timestamp.class)) { Timestamp t1=(Timestamp) p1.getData(); Timestamp t2=(Timestamp) p2.getData(); if(t1.before(t2)) return -1; if(t1.equals(t2)) return 0; return 1; } //Compare Bool if(p1.getData().getClass().equals(Boolean.class)) { boolean b1=((Boolean)p1.getData()).booleanValue(); boolean b2=((Boolean)p2.getData()).booleanValue(); if(b1==false &amp;&amp; b2==true) return -1; if(b1==b2) return 0; return 1; } return 0; } }; </code></pre> <p>Any suggestions to this or different approaches a very welcome.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload