JTableHeader + TableRowSorter Customization
Okay guys, need some help here.
I am trying to customize first of all a TableRowSorter to display sectional header information like in Windows Media Player or Explorer when you group data.
Here is a screen shot: [url]http://www.geocites.com/icewalker2g/images/aaesshot1.jpg[/url]
So far so good with rendering but the table sorting is not working as expected.
Here is screen shot 2: [url]http://www.geocites.com/icewalker2g/images/aaesshot2.jpg[/url]
These are the required sources for the rendering and sorting of the JTable.
1. TitledSeparator:
2. LineSeparatorRowSorter:
3. LibTableCellRenderer:
I put everything together as a neat little file which you can download here: http://www.geocities.com/icewalker2g/downloads/rowsorter.zip
The problem is a bit hard to explain cause I dont know where to look as at now. If anyone can help, I'll be glad. Here is a small sample application to test the code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.filechooser.*;
import javax.swing.border.*;
import javax.swing.table.*;
import java.util.*;
publicclass RowSorterTestextends JFrame{
LineSeparatorRowSorter rowSorter;
LibTableCellRenderer renderer =new LibTableCellRenderer();
public RowSorterTest(){
super("Row Sort Test");
createUI();
}
publicvoid createUI(){
Vector<Object> rows =new Vector<Object>();
for(int i = 0; i < 10; i++){
Vector<String> row =new Vector<String>();
for(int j = 0; j < 4; j++){
row.addElement("Item " + i +" " + j +".htm");
}
rows.addElement( row );
}
Vector<String> cols =new Vector<String>();
cols.addElement("File Name");
cols.addElement("File Description");
cols.addElement("File Location");
cols.addElement("File Size");
DefaultTableModel model =new DefaultTableModel(rows, cols);
JTable table =new JTable( model ){
public TableCellRenderer getCellRenderer(int row,int col){
return renderer;
}
};
table.setRowSorter( rowSorter =new LineSeparatorRowSorter( table ) );
table.setShowGrid(false);
rowSorter.sort();
JScrollPane scroll =new JScrollPane( table );
getContentPane().add( scroll );
pack();
}
publicstaticvoid main(String[] args){
new RowSorterTest().setVisible(true);
}
}
I hope someone can take a wack at this problem cause its been driving me nuts for like 48 hours now.
Thanks in advance for any help given.
# 2
My Bad with the links. I believe was in a haste when I typed them.
Screenshot 1: http://www.geocities.com/icewalker2g/images/aaesshot1.jpg
Screenshot 2: http://www.geocities.com/icewalker2g/images/aaesshot2.jpg
However, I was going about this the wrong way. I did not need to mess around with the RowSorter in anyway, I only needed to deal with the renderer.
I rewrote the code, and focussing on the renderer only and voila. Instant success. Now I can sort and filter with the necessary row separator. It still has relevant bugs in it but it is better than a no show.
I'll make sure to post it on my site when it is complete.
Here is the somewhat buggy code. The WindowFileSystem class and all other relevant classes can found in this zip file: http://www.geocities.com/icewalker2g/downloads/rowsorter.zip
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.filechooser.*;
import javax.swing.border.*;
import javax.swing.table.*;
import javax.swing.tree.*;
import java.io.*;
import java.sql.*;
import java.util.*;
public class LibTableCellRenderer extends DefaultTableCellRenderer {
private FileSystemView sysView = FileSystemView.getFileSystemView();
private WindowsFileSystem fileSystem = new WindowsFileSystem();
JTable table = null;
boolean isOnRow = false;
int currentHighlightRow = -1, sortColumn = 0, titleRow = -1;
Object rowValue = "";
Vector<Integer> sepRows = new Vector<Integer>();
Vector<String> sepTitles = new Vector<String>();
TitledSeparator tsep = null;
public LibTableCellRenderer() {
super();
}
public void attachListener() {
/*table.addMouseListener(new MouseAdapter() {
public void mouseEntered(MouseEvent e) {
isOnRow = true;
}
public void mouseExited(MouseEvent e) {
isOnRow = false;
currentHighlightRow = -1;
table.repaint();
}
});
table.addMouseMotionListener( new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
isOnRow = true;
currentHighlightRow = table.rowAtPoint( e.getPoint() );
table.repaint();
}
});*/
table.getTableHeader().addMouseListener( new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
sortColumn = table.columnAtPoint( e.getPoint() );
System.out.println("Sort Column: " + sortColumn);
//setSortColumn(sortColumn);
}
});
table.getRowSorter().addRowSorterListener( new RowSorterListener() {
public void sorterChanged(RowSorterEvent e) {
if(e.getType() == RowSorterEvent.Type.SORTED ) {
createRowSeparators();
System.out.println("Seperator Rows Recreated");
}
}
});
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int col) {
if(this.table == null) {
this.table = table;
attachListener();
createRowSeparators();
}
String repValue = "";
if(value == null) {
repValue = " ";
} else {
repValue = value.toString();
}
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
setText( repValue );
setIcon( new EmptyIcon(1,16) );
setHorizontalAlignment(JLabel.LEFT);
setForeground( table.getForeground() );
if(isOnRow && currentHighlightRow == row) {
setBackground( new Color(220, 240, 250) );
} else {
if(row % 2 == 0) {
setBackground( new Color(232,242,252) );
} else {
setBackground(Color.white);
}
}
if( value != null && table.getColumnName(col).equalsIgnoreCase("File Size") ) {
try {
int filePathCol = TableUtilities.getColumnIndex( table.getModel(), "File Path" );
value = FileUtilities.getFileSizeAsString( new File( table.getModel().getValueAt( table.convertRowIndexToModel(row), filePathCol).toString() ), "KB");
} catch(Exception e) {}
setText(value.toString());
setHorizontalAlignment(JLabel.RIGHT);
} else if( value != null && table.getColumnName(col).equalsIgnoreCase("File Name") ){
String text = value.toString();
String ext = text.substring( text.lastIndexOf(".") + 1, text.length() );
setIconTextGap(7);
setIcon( getFileIcon(ext) );
setText( text.substring(0, text.lastIndexOf(".") ) );
setBorder( new EmptyBorder(1,5,1,1) );
}
if(isSelected) {
setBackground( new Color(51, 153, 255) );
setForeground( Color.white );
}
//if(col == sortColumn && !repValue.equalsIgnoreCase(rowValue.toString())) {
// rowValue = repValue;
// titleRow = row;
//}
if( sepRows.contains(row) ) {
if(col == 0) {
tsep = new TitledSeparator( sepTitles.elementAt( sepRows.indexOf(row) ) );
} else {
tsep = new TitledSeparator("") {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(comp != null) {
int width = getWidth();
int height = getHeight();
FontMetrics fm = g.getFontMetrics(getFont());
//int strWidth = (int)fm.getStringBounds(getText(), g).getWidth();
int strWidth = comp.getWidth();
int rectWidth = getWidth(), rectHeight = 2;
g.setColor( defaults.getColor("Separator.highlight") );
g.fillRect(width - rectWidth, height/2, rectWidth, 2);
g.setColor( defaults.getColor("Separator.foreground") );
g.fillRect(width - rectWidth, height/2, rectWidth, 1);
}
}
};
tsep.setBorder( null );
((JComponent)tsep.getComponent()).setBorder(null);
}
JPanel panel = new JPanel( new BorderLayout() );
panel.setBorder(null);
panel.setBackground(Color.white);
panel.add( tsep );
panel.add( this, BorderLayout.SOUTH );
table.setRowHeight( row, 45 );
return panel;
} else {
if(table.getRowHeight(row) != 20)
table.setRowHeight(row, 20);
}
return this;
}
public void setSortColumn(int column) {
this.sortColumn = column;
createRowSeparators();
}
public void createRowSeparators() {
if(table == null) {
return;
}
sepRows.removeAllElements();
sepTitles.removeAllElements();
Object rv = "";
for(int i = 0; i < table.getRowCount(); i++) {
Object value = table.getValueAt( i, sortColumn);
if(!value.equals(rv)) {
sepRows.addElement(i);
sepTitles.addElement(value.toString());
rv = value;
}
}
rv = null;
}
public Icon getFileIcon(String ext) {
File f = new File(fileSystem.getTempFolder(), "f." + ext);
if(ext.equalsIgnoreCase("folder")) {
f = new File(fileSystem.getTempFolder(), "mmptmp");
f.mkdir();
} else {
try {
f.createNewFile();
} catch(IOException ioe) {}
}
return sysView.getSystemIcon(f);
}
}
ICE