JTable 的排序+过滤+渲染

首先,jtable本身只是一个框架,它是根据tablemodel来显示数据的,我们能看到几行,table就有几行,但tablemodel

并非如此,因为可能只显示了其中的几行。


排序:

从jdk1.6开始,jtable可以通过点击header来排序了!使用方法如下:

TableRowSorter sorter= new TableRowSorter(tablemodel); 
jtable.setRowSorter(sorter);
可见,TableRowSorter需要一个底层的tablemodel来装载数据。一般选择重写tablemodel的方法来自定义排序规则,加快排序速度:

DefaultTableModel tablemodel = new DefaultTableModel(obj,goodsInfo)
				{
					private static final long serialVersionUID = 1L;
					//--设置不可编辑-------
					public boolean isCellEditable(int row,int column)
					{
						return false;
					}
					//--定义按类的比较规则排序---------
					public Class getColumnClass(int column) {  
				        Class returnValue = Object.class;  
				        if ((column >= 0) && (column < getColumnCount())&& (getRowCount()>0)) 
				        {	//排除某些cell是空的情况
				        	for(int i=0;i

过滤:

TableRowSorter有个方法是setRowFilter,可以实现过滤,它继承自DefaultRowSorter,使用方法:

sorter.setRowFilter(RowFilter.regexFilter(".*foo.*"));
可以用正则表达式来过滤。

这时候,我们看到的行数变了,即table.getRowCount()变了,但底层的tablemodel行数是不会变的!


接下来,讲另一个问题,排序或者过滤后,选择的那一行的数据和原来的可能有变化,这时,如果还是用table.getSelectedRow()得到的行索引,和实际该数据在tablemodel中的索引不一样,举个例子:
(内容乱写的...)
JTable 的排序+过滤+渲染_第1张图片

开始时的样子,未做任何处理,即model和table统一。

JTable 的排序+过滤+渲染_第2张图片

按单价排序,顺序发生变化,看左边的显示。


按关键字进行过滤,再按单位排序,看左边的显示。

结论:只要model不变,里面的数据无论怎么排序、筛选,顺序都是不变的。我们看到的只是table的变化。


ps:将table中选中行的索引转换成model中的索引方法:

int row_real = table.convertRowIndexToModel(table.getSelectedRow());
类似地,要在基于底层模型model坐标的 JTable 中选择一行或多行,执行以下相反的操作:

 
  
table.setRowSelectionInterval(table.convertRowIndexToView(3),table.convertRowIndexToView(4));
这里3和4即为底层model的索引,无论外界条件怎么变,该方法都会找到3和4对应与视图jtable中的索引。
 
  列同理。另:自己编写DefaultTableModel时也要注意,重写方法里面的行列都是指model的行列,例如要使 
  
table某一cell可编辑(原来都是不可编辑),则输入的i,j应为model的,例如现在要渲染选中行的"单价"单元格,
自定义DefaultTableModel:
class My_tablemodel extends DefaultTableModel
{
	private static final long serialVersionUID = 1L;
	private int i=-1,j=-1;
	//--设置不可编辑-------
	 My_tablemodel(Object[][] obj,String[] str)
	 {
		 super(obj,str);
	 }
	public boolean isCellEditable(int row,int column)
	{
		if(row==i&&column==j)return true;
		return false;
	}
	//--定义按类的比较规则排序---------
	public Class getColumnClass(int column) {  
        Class returnValue = Object.class;  
        if ((column >= 0) && (column < getColumnCount()&& getRowCount()>0)) 
        {	
        	for(int i=0;i
使用:
My_tablemodel.setij(row,column);
table显示时会自动转换!

来自DefaulTableModel源代码的警告:
Warning:
DefaultTableModel returns a column class of Object. When DefaultTableModel is used with a
TableRowSorter,this will result in extensive use of toString, which for non-String data 
types is expensive. 
If you use DefaultTableModel with a TableRowSorter you are strongly encouraged to override 
getColumnClass to return the appropriate type.
这告诉我们,如果不重写getColumnClass方法,java默认使用Object的toString方法比较元素大小,除了

AbstractTableModel类:
public Class getColumnClass(int columnIndex) {
        return Object.class;
}
DefaultTableModel类并没有再次覆盖这个方法。


渲染:

JTable有个方法叫setDefaultRenderer(),下面是该方法的定义:
 
  
public void setDefaultRenderer(Class columnClass, TableCellRenderer renderer) {
        if (renderer != null) {
            defaultRenderersByColumnClass.put(columnClass, renderer);
        }
        else {
            defaultRenderersByColumnClass.remove(columnClass);
        }
    }
其中columnClass是选择要将哪些列进行渲染,列默认的类为Object.class,当然也可以自己在tablemodel中重载getColumnClass方法来进行定义。
renderer是此 columnClass 要使用的默认单元格渲染器,可自己定义。
从源代码中可以看出,他使用了一个HashTable来存<类,渲染器>,如果将renderer设为null,则去掉相应该类的渲染器。
(此处类是指属于该类的列)
下面是自己定义的一个TableCellRenderer,通过传入两个参数i,j来使那个单元格变色:
class My_TableCellRender implements TableCellRenderer
{	
	private int i=-1,j=-1;
	My_TableCellRender(int i,int j)
	{	
		super();
		this.i = i;
		this.j = j;
	}
	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
		Component renderer = new DefaultTableCellRenderer().getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);     
		Color foreground, background;    
	    
		if(row==i&&column==j)
		{	
		    foreground = Color.RED;
		    background = Color.green;
		    renderer.setForeground(foreground);     
		    renderer.setBackground(background); 
		}  
	       return renderer; 
	}
}
使用方法:
table.setDefaultRenderer(Object.class, new My_TableCellRender(row,column));
时遇到了一个问题,只有属于String那几列的被修饰了,Integer和Float的没有。
而换成:
table.setDefaultRenderer(Integer.class, new My_TableCellRender(row,column));
或者:
table.setDefaultRenderer(Float.class, new My_TableCellRender(row,column));
都只是渲染了该类的列,按道理说Object.class不是应该全部渲染的吗???

这是重写的DefaultTableModel:
public Class getColumnClass(int column) {  
        Class returnValue = Object.class;  
        if ((column >= 0) && (column < getColumnCount()&& getRowCount()>0)) 
        {	
        	for(int i=0;i
如果将if语句注释掉,即全部返回Object.class,则全部列可渲染,但无法排序了...
一个神奇的问题,有空再研究研究...


你可能感兴趣的:(JAVA)