Hello all,
I am trying to add a custom row sorter to my project. When the user clicks to sort a table, i want it to actually sort the underlying list, not the view. I feel i have implemented this, following what the docs for RowSorter say for databases, and just make a RowSorter that interfaces with your database.
The problem is when i add my custom RowSorter, i get a NullPointerException way up in Suns code. And i dont have that source code or know how to get it to investigate what it is doing.
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at sun.swing.table.DefaultTableCellHeaderRenderer.getTableCellRendererComponent(DefaultTableCellHeaderRenderer.java:69)
I have even tryed setting a DefaultRenderer for the Header (see line 81), but i still get the same exception.
I have made a short example app that will show you what im seeing.
Comment out line 77 and you will see it runs fine without the custom RowSorter.
Thanks for you help,
Will
// BEGIN CODE EXAMPLE
package test1;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.RowSorter;
import javax.swing.RowSorter.SortKey;
import javax.swing.table.AbstractTableModel;
public class Main extends javax.swing.JFrame implements Runnable {
private ArrayList<String> data = new ArrayList<String>();
/** Creates new form Main */
public Main() {
}
public static void main(String... args) {
EventQueue.invokeLater(new Main());
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jTable1 = new javax.swing.JTable();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jScrollPane1.setViewportView(jTable1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
public void run() {
initComponents();
// just filling my data list with random strings
Random r = new Random();
for (int i = 0; i < 20; ++i) {
data.add(Integer.toHexString(r.nextInt()));
}
initMyTableStuff();
this.setVisible(true);
}
private void initMyTableStuff() {
jTable1.setModel(new MyTableModel());
// the app runs just fine without the next line
jTable1.setRowSorter(new MyRowSorter());
// i dont think i should have to set a default header renderer, the docs
// say that when its null it will use the default renderer.
//jTable1.getColumnModel().getColumn(0).setHeaderRenderer(jTable1.getTableHeader().getDefaultRenderer());
}
private class MyRowSorter extends RowSorter<MyTableModel> {
List<? extends SortKey> keys = null;
@Override
public Main.MyTableModel getModel() {
return (MyTableModel) jTable1.getModel();
}
@Override
public void toggleSortOrder(int column) {
Collections.sort(data);
}
@Override
public int convertRowIndexToModel(int index) {
return index;
}
@Override
public int convertRowIndexToView(int index) {
return index;
}
@Override
public void setSortKeys(List<? extends SortKey> keys) {
this.keys = keys;
}
@Override
public List<? extends SortKey> getSortKeys() {
return keys;
}
@Override
public int getViewRowCount() {
return getModelRowCount();
}
@Override
public int getModelRowCount() {
return jTable1.getModel().getRowCount();
}
@Override
public void modelStructureChanged() {
}
@Override
public void allRowsChanged() {
}
@Override
public void rowsInserted(int firstRow, int endRow) {
}
@Override
public void rowsDeleted(int firstRow, int endRow) {
}
@Override
public void rowsUpdated(int firstRow, int endRow) {
}
@Override
public void rowsUpdated(int firstRow, int endRow, int column) {
}
}
private class MyTableModel extends AbstractTableModel {
public int getRowCount() {
return data.size();
}
public int getColumnCount() {
return 1;
}
public String getColumnName(int columnIndex) {
return "DATA" + columnIndex;
}
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return data.get(rowIndex);
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
data.set(rowIndex, (String) aValue);
}
}
// Variables declaration - do not modify
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTable jTable1;
// End of variables declaration
}
// END OF CODE EXAMPLE