5

I have a JXtable. I would like to prevent the top 3 rows from being sorted. Basically the top 3 rows should always be on top and the remaining ones should be sorted according to their value.

There is a similar question on SO but i am not sure how to really apply it to my use Sort ROW except last row

The major difference is that i am using JXTable. Is there a easy way to do this that i am missing?

Here is my JXtable code

jTable1 = new JXTable();
if (isClickable) {
    jTable1.getTableHeader().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

    //set the sorter here
} else {
    jTable1.setSortable(false);
}
Community
  • 1
  • 1
codeNinja
  • 1,442
  • 3
  • 25
  • 61
  • http://stackoverflow.com/questions/11665397/jtable-multiple-header-rows – Joop Eggen Mar 18 '14 at 13:53
  • not sure if that link applies. That one is referring to grouping of headers. Any comment on why you think its similar or any particular section of that thread i should re-read? – codeNinja Mar 18 '14 at 17:28
  • I thought having multi-row headers might just be like having top rows fixed on sorting. _Thanks, a next time will ellaborate more._ – Joop Eggen Mar 19 '14 at 06:39

1 Answers1

1

Well, it took me a little while to perfect this as best I could, but here's my working example.

Basically, I made a wrapper class called ComparableWrapper that implements Comparable so the sorting for each column could be manipulated. For the table model, I added a setData(Object[][] data) method that automatically wraps all the data values in a ComparableWrapper. The sorted argument in the ComparableWrapper contructor determines whether the value should be sorted as normal, or stay at the top no matter what.

You'll have to manually change the class types for the columns in a few places. Anyway, here's my SSCCE:

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.table.AbstractTableModel;
import org.jdesktop.swingx.JXTable;

public class TableTest extends JFrame {

    public TableTest() {
        super("JXTable - first 3 rows aren't sorted");
        setLayout(new BorderLayout());

        MyTableModel model = new MyTableModel();
        JXTable table = new JXTable();
        table.setModel(model);

        Object[][] initialData = {
            {"Zoe", new Integer(26)},
            {"Adam", new Integer(29)},
            {"Trisha", new Integer(33)},
            {"Reed", new Integer(20)},
            {"John", new Integer(3)},
            {"Kyle", new Integer(102)},
            {"Billy Bob", new Integer(27)},
            {"Sandra", new Integer(87)},
            {"Steve", new Integer(50)},
            {"Guy", new Integer(23)},
            {"Kenzie", new Integer(25)},
            {"Mary", new Integer(27)},
            {"Sally", new Integer(12)},
            {"Joe", new Integer(101)},
            {"Billy", new Integer(44)},
            {"Bob", new Integer(83)},
        };
        model.setData(initialData);

        JScrollPane tableScroll = new JScrollPane(table);
        add(tableScroll, BorderLayout.CENTER);

        table.setFillsViewportHeight(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(400, 600);
        setVisible(true);
        setLocationRelativeTo(null);
    }

    private class MyTableModel extends AbstractTableModel {

        String[] columns = { "First Name", "Age" };
        Object[][] data = {};

        public void setData(Object[][] data) {
            for (int i=0; i<data.length; i++) {
                // Don't sort top 3 rows
                boolean sorted = i < 3 ? false : true;

                // Wrap each object so the sorting can be manipulated.
                // Change these class types as needed.
                data[i][0] = new ComparableWrapper<String>((String) data[i][0], sorted);
                data[i][1] = new ComparableWrapper<Integer>((Integer) data[i][1], sorted);
            }
            this.data = data;
            fireTableDataChanged();
        }

        @Override
        public Class<?> getColumnClass(int col) {
            return ComparableWrapper.class;
        }

        @Override
        public int getColumnCount() {
            return columns.length;
        }

        @Override
        public int getRowCount() {
            return data.length;
        }

        @Override
        public Object getValueAt(int row, int col) {
            return data[row][col];
        }

        @Override
        public String getColumnName(int col) {
            return columns[col];
        }

    }

    private class ComparableWrapper<T> implements Comparable<ComparableWrapper<T>> {

        private Comparable<T> object;
        private boolean sorted;

        public ComparableWrapper(Comparable<T> object, boolean sorted) {
            this.object = object;
            this.sorted = sorted;
        }

        @Override
        public int compareTo(ComparableWrapper<T> o) {
            if (object instanceof Comparable<?>) {
                if (sorted && o.isSorted()) {
                    // Sort normally by default
                    return object.compareTo(o.getObject());
                } else {
                    // If an un-sorted row is being compared, don't compare at all
                    return 0;
                }
            }

            // Fallback
            return 0;
        }

        public T getObject() {
            return (T) object;
        }

        public boolean isSorted() {
            return sorted;
        }

        @Override
        public String toString() {
            return object.toString();
        }

    }

    public static void main(String[] args) {
        new TableTest();
    }

}
uyuyuy99
  • 353
  • 4
  • 11
  • When i run this no data gets added to the jxtable. – codeNinja Mar 25 '14 at 00:05
  • @codeNinja Sorry, I forgot to add `fireTableDataChanged();` to the `setData` method on the table model. That way it'll notify the table that the data updated. I've updated my answer. – uyuyuy99 Mar 25 '14 at 01:55
  • `fireTableDataChanged` populated the table. Now when i click the header with the names i get the following error: `Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javaapplication4.JavaApplication4$ComparableWrapper cannot be cast to java.lang.String` – codeNinja Mar 25 '14 at 02:38
  • @codeNinja Sorry, I forgot about another small update I made - the `classes` array in the table model is not actually needed at all. Just change the `getColumnClass` method to return `ComparableWrapper.class`. I've updated my answer to reflect this. – uyuyuy99 Mar 25 '14 at 03:19
  • Thank You! Excellent answer with a working example. The bounty goes to you. – codeNinja Mar 25 '14 at 13:50