让某些单元格不可编辑

有些时候,我们希望有些行/列可以被编辑,而有些行/列不能被编辑。如下就是一例,我的程序希望第一列(编号列)的内容可以被用户通过双击进行编辑,而其他列则不能被用户编辑。单元格能否被编辑取决于JTable的isCellEditable(int row,int column)。如果该函数返回true则(row,column)所代表的单元格可以被编辑,否则该单元格不能被编辑。于是我建立了一个名为SingleUnitEditableTable的类,他继承自JTable,并Overwrite了isCellEditable(int row,int column)方法:

//设置单元格不可编辑,为缺省实现
    public boolean isCellEditable(int row, int column) {
        if( editableColumn != -1){
            if( column == editableColumn )
                return true;
            return false;
        }
        return false;
}

其中的editableColumn是一个内部属性,用来指定哪个列可以被编辑。通过这个例子,我相信,如果你想实现奇数行/列可编辑而偶数行/列不可被编辑或者满足特定条件的单元格不可被编辑这样的JTable易如反掌了吧?下面就是我的应用程序的结果:

 

第一列可编辑

 

其他列均不可编辑

    JTable自排序

这个问题已经由JDK6.0帮我们解决了,在这个版本,JDK为我们提供了一个名为TableRowSorter的类,在程序中我们只需要写2行代码即可实现表格内容的排序:

TableRowSorter sorter = new TableRowSorter(tableModel);
       accAllTable.setRowSorter(sorter);

看到“编号”列旁边的箭头了吗?如果我们用鼠标点击表头,JTable就会自动为我们由小到大排序,再点一下,表格就会从大到小排序,真是十分方便。而对于JDK6.0之前的应用程序就没有这么好的运气了,我们需要自己实现一个TableRowSorter,并且自己生成一个表头的Renderer来实现排序小箭头,真是繁琐啊!我这里倒是有一个不错的实现,如果有人需要的话可以给我留言。不过自己实现Renderer采用的是JLabel,会改变表头的模样,不如默认的表头好看,所以可能的话还是升级吧J

 

 

 

5       用JEditorPane显示HTML描述的文本

从JDK1.4开始,Swing的很多组件(如JLabel)都可以显示HTML语言写的文本。这是一个巨大的进步,因为我们可以将所要显示的文字的配置信息如字体,字号,颜色,换行等信息直接以HTML写入到组件的setText()方法当中,不但免去了事后对这些信息进行繁杂配置的烦恼,而且还丰富和简化了所要显示文本的形式。而JEditorPane则有所不同,它天生就是用来分析并显示格式化文本的,由一些Java写的开源Web浏览器甚至都采用改进后的JEditorPane作为Web页的显示器。下图就是SwingSet2中的JEditorPane相关的例子。我们可以看到JEditorPane可以显示大多数的HTML元素,包括图片,格式化文字,URL链接等。

 

然而通过JEditorPane显示HTML描述的文本有两种方式:

第一种是直接使用JEditorPane.setPage(String htmlTxt);来显示用html语言写成的文本。但是这种方法的缺点是无法显示HTML文本中所描述的对外部资源(如图片,CSS等)的引用。所以如果要显示更为丰富的信息,仅仅用第一种方法是不够的。

       所以第二种方法就呼之欲出:将用HTML语言描述的动态文本信息写到文件中,使之成为真正的HTML文件,再用JEditorPane.setPage(URL)或JEditorPane.setPage(String htmlFilePath),JEditorPane方法读入这个动态生成的内容文件就可以让JEditorPane自动为我们显示丰富的信息了。

String vNewReportFileName = "file:///c:/temp.html";
   JEditorPane reportPane = new JEditorPane();
   File f = new File(FileUtil.reportDir,vNewReportFileName);
  FileWriter fw = new FileWriter(f, false);
   fw.write("");
  fw.write("");
  …………
  fw.write("");
//清理操作
   fw.flush();
   fw.close();
  f = null;
reportPane.setPage(vNewReportFileName);

下图就是我的程序所显示的结果,从图中我们可以清楚地看到由CSS文件定义的表格的Title,这个Title是由一个蓝色的图片作为背景的。

 

让人遗憾的是用JEditorPane显示的表格的边框都很粗,虽然我已经将了表格的border设置为1,可是JEditorPane依然我行我素。但是在IE下,表格的边框的表现就要好的多:

 

网上有人说这是一个Bug,但是没有人给过解决这个问题的方法,如果有人又解决方法的话请留言,我将不胜感激!




6       用InfiniteProgressPanel实现GlassPane

俗话说重要人物都最后出场,作为Swing篇的完结部分,我为大家隆重推荐一个GlassPane的实现—InfiniteProgressPanel,它的效果如图所示:

 

怎么样,很酷吧?这是在程序进行更新的时候能够给用户以提示,可以屏蔽用户操作而且十分美观的特殊进度条。它源于一个超级Java大牛的手笔,此君的《Swing Hacker》在去年如带给我的震撼到现在还挥之不去。从那以后,谁再敢说Java不能做出好看的用户界面之前都需要自己好好掂量一下自己是否有这么说的资格。这本书让我真正认识到,只有想不到没有做不到。都是一样用Swing,为啥人家就能玩出花样呢?差距!

其实现原理很简单,说白了就是用Java2D画圈!至于源码各位可以到网上自己搜。他的使用十分简单:

InfiniteProgressPanel glassPane = new InfiniteProgressPanel();
frame.setGlassPane(glassPane)

在需要它显示的时候,就这样做:

Thread myThread = new Thread(new Runnable(){
         public void run()  {
              InfiniteProgressPanel gl = thisRef.glassPane;
              gl.start();
              gl.setText("正在保存数据请稍候....");
              try {
                 //这里放要做的事情……
                 gl.setText("保存完毕,欢迎使用!");
                 Thread.sleep(1000);
               }catch(InterruptedException ex) {
               }finally{
                 gl.stop();
               }
            }
    });
myThread.start();

这里有几个问题需要注意:

1.         必须要将InfiniteProgressPanel的显示放到一个线程里,相信大家都知道原因,我不用多说。

2.         在InfiniteProgressPanel结束之前的Thread.sleep(1000);是必要的,如果时间设得太短或不设将会导致InfiniteProgressPanel死掉。至于原因我没有时间深究,各位有兴趣可以自行察看其源码,如果你能找到原因高诉我,我会非常感激。

3.         在有些时候会出现圆圈“四处乱窜”的现象,不过不太常见。