首先,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中的索引不一样,举个例子:
(内容乱写的...)
开始时的样子,未做任何处理,即model和table统一。
按单价排序,顺序发生变化,看左边的显示。
按关键字进行过滤,再按单位排序,看左边的显示。
结论:只要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方法来进行定义。从源代码中可以看出,他使用了一个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,则全部列可渲染,但无法排序了...
一个神奇的问题,有空再研究研究...