自学自用Greasemonkey

使用Firefox的用户应该比较熟悉 Greasemonkey 这个插件吧,但是大部分估计都是使用一些网上的脚本,最近无意中突然发现 Greasemonkey 其实是非常的好用,也完全可以在自己常用的网站上自己调整使用。

比如使用 Windows Live Mail 网页版时,右侧总有讨厌的广告,以及左下角,多关闭几次,它还提醒你升级到 Plus版本,真不爽,但是这类广告firefox的广告拦截插件又不能过滤掉,那么用 Greasemonkey 就非常简单了,可以很简单的屏蔽到广告的显示,当然这中间需要用到一些HTML,javascript,dom等相关知识。例如下面简单的几句代码可以做到让右侧广告不显示:

var ad = document.getElementById('MainContent');
if(ad){
    ad.style.right='0px';
}

对于完全没有概念的同学,推荐可以阅读这本书(深入浅出Greasemonkey),在线的,内容非常简洁:http://www.firefox.net.cn/dig/

或者参见这里:http://wiki.greasespot.net/Tutorials

Enjoy yourself

[10/22 周主题] – 强悍的JQuery Validate 插件

对于JQuery Validate,只有相见恨晚的感触,恐怕在表单验证领域这是目前我见过最好的插件了,可以很方便的使用,极大的提高表单验证的效率。

下面就介绍下简单的使用方法:

1、下载地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation/,本文章发布时最新版是1.7。

2、在页面里面加载JQuery和JQuery Validate

<script type="text/javascript" src="theme/default/js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="theme/default/js/jquery.validate.min.js"></script>

3、写一个表单提交页面,form id 为 login,两个提交域email和password。域提供相应的id。为了完善demo,我在里面也提供了一个注册的form,同时提供了自定义验证方法和ajax提交。

继续阅读[10/22 周主题] – 强悍的JQuery Validate 插件

[10/08周主题] – JQuery分页导航条插件

之前在写 [10/02周主题] – 仿Gmail头像上传剪辑 时说,还有个JQuery的分页组件分享给大家,这个组件是别人设计的,我只是在其基础上,进行一些改动,以符合自身项目的需求。

之前在做Web项目时,分页功能的处理是放在服务器端,客户端只是用来显示分页导航条内容。 虽然将服务器端的分页功能进行封装,页码显示代码也进行了整理,但是总归不是很方便,做分页功能还是要做不少工作。

后来去看一些将分页功能放在客户端处理的例子,最后发现了这个比较不错的JQuery组件(如果你有好的方案也欢迎分享啊),原文章在这里:http://lym6520.javaeye.com/blog/540580,我就不做过多介绍了。

通过这个组件做分页功能,服务器端几乎不做什么处理,只需要显示数据列表时把总数传给该组件即可。至于分页组件的样式你完全可以自己去定制。

下面分享下自己的一些优化工作:

1、Loading和错误提示

Loading和错误信息的显示在获取数据时控制,这里用到了Ajax的几个状态来判断,比如beforeSend,success以及error。

2、分页组件的翻页和获取数据是异步的,这样如果出现服务器问题,无法获取翻页后的信息,但是分页导航条已经做了翻页了。由于服务器出错是在Ajax里面捕获的,这样就只能做个hack,通过dom操作来让翻页返回去,最终的效果会是这样的:假如现在在第三页,要跳转到第四页,点 “4” 翻页了,然后发现翻页后无法获取数据,出现服务器问题了,接着就又返回第三页了,显示错误信息。

[09/49周主题] – Swing Tips

择这个主题,是因为上周公司刚好做了一个有关“Beginning Java AWT and Swing” 的培训,借此机会正好总结一下这方面的使用技巧。对于Swing界面方面的研究,我仅仅是应用而已,公司里有几位同事在这方面的研究比较深,这块的应用和使用技巧分两部分, 一部分是Swing 使用本身的,另一部分是Design工具NetBeans的,如果是刚入门建议从这里看起:Creating a GUI With JFC/Swing

本期主题:Swing Tips

一、性能问题

随着Java 6对于Swing性能的改进,Swing的运行速度已经开始得到了大大的提高,看看NetBeans就知道了,NetBeans就是Swing开发的,如果你跑Swing很慢,很耗资源,那么应该从自己的程序上找找问题,推荐使用NetBeans自带的Profile查找原因,教程在这里 – Profile Introduce

二、LookAndFeel

用Swing做企业应用时,LookAndFeel的选择和使用是决定这个项目能否被客户接受的一个很大因素,即要好看,又要考虑跨平台的兼容性,必要时自己还得设计部分LookAndFeel, 可以看看这里提供的一些开源LookAndFeel:http://www.open-open.com/61.htm 和http://www.javootoo.com/。
切换LookAndFeel:

UIManager.setLookAndFeel(LookAndFeelName);
SwingUtilities.updateComponentTreeUI(frame);
frame.pack();

三、合理的控制初始化组件和组件初始化的顺序可以很大的提高性能

举个例子:之前我们项目中有一个地方,当打开程序时,会初始化几十个甚至成百个JPanel,这显然成为程序启动时慢的一个因素,也导致了用户体验的降低,这些JPanel完全可以在程序启动后再根据用户的需要去初始化,因为用户打开程序时这些Panel不是必须看到的。

四、要有统一的UI规范

比如Button的高度,进度条的高宽等,也可以通过UIManager给系统组件设置统一属性,比如统一设定Button的间距和字体:

UIManager.put("Button.margin", new Insets(2, 5, 2, 5));
UIManager.put("Button.font", new Font("宋体", Font.PLAIN, 13));

五、多线程的使用

用Swing做的都是界面的东西,如果界面假死或者用户等待事件太长,那么用户体验必然是不好的,这里就需要用到多线程的使用了,当界面处理一个请求时,不能让界面假死了,需要后台另一个线程去做处理,然后将结果返回到Swing线程,这块可以看看SwingWorker的介绍。

六、布局管理器

布局管理器的使用在Swing里面是比较重要的,它直接决定了你界面的显示效果,也是比较难用的一块,不好举例子,建议多了解每个布局管理器的使用场景。

七、JTable & JTree

在Swing组件的使用中除了布局管理器,估计就数JTable和JTree的使用稍微有点麻烦了,下面我就分享一些实际项目中JTable的一些实例,关于JTree,可以点这里:JTree 经验 总结

JTable相关

1、自定义表头排序
TableRowSorter rs = (TableRowSorter) table.getRowSorter();
Comparator<Integer> intComparator = new Comparator<Integer>() {

            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        };
rs.setComparator(3, intComparator);
 
2、自定义Table Renderer
public class CommonTableCellRenderer extends DefaultTableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean cellHasFocus, int row, int column) {
            JComponent comp = (JComponent) super.getTableCellRendererComponent(table, value,
isSelected, cellHasFocus, row, column);
            //表格的奇数偶数行交叉颜色显示
            if (!isSelected) {
                if (row % 2 == 0) {
                    comp.setBackground(UIConsts.HIGHLIGHTER_COLOR);
                } else {
                    comp.setBackground(Color.white);
                }
            }

            //table column里面显示图标和对齐方式
            switch (column) {
                case PaperTableModel.STATUS_COLUMN:
                    switch ((EntityStatus) value) {
                        case VALID:
                            comp.setIcon(ENABLED_ICON);
                            setHorizontalAlignment(JLabel.LEADING);
                            break;
                        case DISABLED:
                            comp.setIcon(DISABLED_ICON);
                            setHorizontalAlignment(JLabel.CENTER);
                            break;
                    }
                    break;
                default:
                    comp.setIcon(null);
                    break;
            }

            return comp;
        }
    }
 
3、自定义Table列宽
TableColumnModel colModel = table.getColumnModel();
colModel.getColumn(0).setPreferredWidth(70);
colModel.getColumn(1).setPreferredWidth(55);
colModel.getColumn(2).setPreferredWidth(120);
4、禁止Table列拖动
 table.getTableHeader().setReorderingAllowed(false);  
5、单选表格设置
 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);   
6、设置表头默认支持排序
 table.setAutoCreateRowSorter(true);  
7、设置列不可随容器组件大小变化自动调整宽度
 table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);  
8、固定Table上的某些列不滚动

这个需求是这样的,比如Table上左边有部分数据,是后面数据所共有的属性,那么当后面数据很多时,显示不下会出现滚动条,但是滚动时又不想让左侧的共有属性动,只滚动右侧的数据部分。
实现原理是:scrollPane里面放置一个表格,然后在scrollPane的左上角放置以共有属性的部分为Model的表格,剩下的右侧就是剩余的纯数据表格。
最终效果就是表格左侧的列锁定了,右侧数据出现滚动条时,可以滚动,但左侧不动。
核心代码:比如有HeaderTable和ReportTable, 其中ReportTable是放置在一个ScrollPanel里面,Model是所有数据的Model,将左侧的数据和右侧的数据分开

//找到主表所在的scrollPane
JScrollPane scrollPane = (JScrollPane) SwingUtilities.
   getAncestorOfClass(JScrollPane.class,
    reportTable.getTable());

//中间处理headerTable的数据和reportTable剩余的数据

//将新表HeaderTable放在scrollPane的左上角
scrollPane.setRowHeaderView(headerTable.getTable());
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
                    headerTable.getTable().getTableHeader());
9、Table上的直接编辑功能

两点:
1、重写 public boolean isCellEditable(int row, int columnIndex) 方法,定义可编辑的行列。
2、重写 public void setValueAt(Object obj, int rowIndex, int columnIndex) 方法,拿到原来的对象,设置新的对象值。

10、Table的Excel导出功能

表格上的Excel导出功能还是比较实用的功能,企业应用一般都会用到,这里提供相关代码

try {
   WritableCellFormat titleFormat = new WritableCellFormat(
   new WritableFont(WritableFont.createFont("黑体"), 16,
   WritableFont.NO_BOLD));
   titleFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐
   titleFormat.setAlignment(Alignment.CENTRE); // 水平对齐
   titleFormat.setWrap(true); // 是否换行

   WritableCellFormat headerFormat = new WritableCellFormat();
   headerFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条
   headerFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐
   headerFormat.setAlignment(Alignment.CENTRE); // 水平对齐
   headerFormat.setWrap(true); // 是否换行

   WritableCellFormat countFormat = new WritableCellFormat(
   new NumberFormat("0.000"));
   countFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条
   countFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐
   countFormat.setAlignment(Alignment.RIGHT); // 水平对齐
   countFormat.setWrap(true); // 是否换行

   WritableCellFormat moneyFormat = new WritableCellFormat(
   new NumberFormat("0.00"));
   moneyFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条
   moneyFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐
   moneyFormat.setAlignment(Alignment.RIGHT); // 水平对齐
   moneyFormat.setWrap(true); // 是否换行

   WritableCellFormat intFormat = new WritableCellFormat(
   new NumberFormat("0"));
   intFormat.setBorder(Border.ALL, BorderLineStyle.THIN); // 线条
   intFormat.setVerticalAlignment(VerticalAlignment.CENTRE); // 垂直对齐
   intFormat.setAlignment(Alignment.RIGHT); // 水平对齐
   intFormat.setWrap(true); // 是否换行

   WritableWorkbook book = Workbook.createWorkbook(exportFile);
   WritableSheet sheet = book.createSheet("综合统计报表", 0);
   int titleRow = 0;
   int headerRow = 3;
   int dataRow = 5;
   sheet.mergeCells(0, titleRow, model.getColumnCount() - 1,
   titleRow);
   Label titleLab = new Label(0, titleRow, tableTitleTxfd.getText(), titleFormat);
   sheet.addCell(titleLab);

   //生成表头
   for (int j = 0; j < model.getColumnCount(); j++) {
       sheet.mergeCells(j, headerRow, j, headerRow + 1);
       Label lab = new Label(j, headerRow, model.getColumnName(
      j), headerFormat);
       sheet.addCell(lab);
   }

   for (int row = 0; row < model.getRowCount(); row++) {
       for (int col = 0; col < model.getColumnCount(); col++) {
          Object obj = model.getValueAt(row, col);
          if (obj instanceof String) {
             Label lab = new Label(col, dataRow + row,
               (String) obj, headerFormat);
            sheet.addCell(lab);
          } else if (obj instanceof Integer) {
         Number labelN = new Number(col, dataRow
         + row, (Integer) obj, intFormat);
         sheet.addCell(labelN);
         } else {
         Label lab =
         new Label(col, dataRow + row, "",
         headerFormat);
         sheet.addCell(lab);
         }
      }
   }

   //生成表尾
   int footerRow = dataRow + model.getRowCount() + 1;
   int step =
   (int) (((double) (model.getColumnCount() - 2) / 3)
   + 1);
   Label footerLab = new Label(0, footerRow, "部门负责人:");
   sheet.addCell(footerLab);
   footerLab = new Label(step, footerRow, "制表:" + creatorTxfd.getText());
   sheet.addCell(footerLab);
   footerLab = new Label(model.getColumnCount() - 2, footerRow,
   NazcaFormater.getSimpleDateString(new Date()));
   sheet.addCell(footerLab);

   sheet.setColumnView(0, 16);
   sheet.setRowView(titleRow, 600);

   book.write();
   book.close();
   //导出成功
   } catch (Throwable ex) {
   //导出报表失败
   ex.printStackTrace();
}
11、Table的打印功能

打印这块,之前已经提过,可以参考之前的文章 JTable Print

12、在Table上选择多行
int rowcounts=table.getSelectedRows().length;
if(rowcounts>1)
  int[] rows=table.getSelectedRows();
    for(int i=0;i<rows.length;i++){
    String value=(String) tableModel.getValueAt(i, 1);
  }
}

NetBeans 6+ Tips

这里说NetBeans,主要是因为目前Swing开发方面,还没有哪个IDE能胜过NetBeans。

一、NetBeans的配置

1、配置为英文,大部分时间我们下载的都是中文的版本,可以通过在/$NetBeans_HOME/etc/netbeans.conf中添加 –locale en_US, 让启动时显示为英文,这个之前也有文章介绍:Netbeans 英文界面最简单的Netbeans中英文切换
2、优化配置可以看之前介绍的这篇文章,就不重复了:Netbeans 6.5 优化建议

二、经验分享

1、Swing的Debug虽然被很多人说不好用,但是在用NetBeans时,多用Debug可以提高效率,因为Debug模式下的修改,大部分只要点击应用,就可以不用重启项目而看到效果。
2、很好用的快捷键和快速补齐(限Windows + Linux下,如果在Mac下改成 ⌘ 试试),如:

快捷键:
Ctrl+R          Rename
Alt+Enter       Fix Error(Eclipse Ctrl+1)
Alt+Shift+F    Quick Format
Alt+Shift+I     Fix Import
F9                Build File
F6                Run Main Project
Shift+F6        Run File
Ctrl+|           Insert Code

快速补齐(英文输入状态下,输入完后按Tab键,也可以自己配置为其他键,在Options - Editor - 
Code Templates下):
psvm            public static void main
sout             System.out.println
im               implements
Psfs             public static final String
psfi             private static final String
fore            for($ : $){}
fori             for(int i = 0; i < arr.length; i++){}
forl             for(int i = 0; i < list.size(); i++){}

三、插件分享
我们都知道NetBeans上的插件很多,可以说NetBeans正是因为这些插件才强大起来,支持的功能也更多了。分享的这几个插件是平时工作时,可以显著提高效率的,不好的不推荐,你如果有好的也别忘记分享下。

1、Path Tools – 可以直接查找到类或者文件夹所在的磁盘位置,基本是我每次装完NetBeans的后第一个装的插件。
2、SQE(Software Quality Environment) – 是最近同事刚刚推荐的一个插件,看名字就知道了,是一个类似Firebug的插件,可以发现程序中存在的一些显著的错误,很不错。
3、UUID Generator – 同事写的一个快速生成UUID的插件。
4、SwingX 插件 – 用来添加一些SwingX组件的。
5、iReport – 打印报表用的插件,结合JasperReport使用。