Swing


天行健 君子以自强不息

posts - 69, comments - 215, trackbacks - 0, articles - 16
   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

JavaSwing也惊艳之一:水晶之恋

Posted on 2009-02-20 00:18 zht 阅读(12008) 评论(24)  编辑  收藏 所属分类: Swing
 

一、序言

关于“Java做不好桌面”的争论已经由来已久。虽然SwingJava2D已经有超过十年的历史,也有JIDEJGoodiesTWaver等不少开源Swing组件,但是用Java做桌面程序仍然不是一件轻松的事。本《Java也惊艳》系列文章,就是想通过一些简单生动的例子,和大家一起认识Java、探索Swing。其实你只需要多一点创意、多一点耐心,你的Java程序也可以“惊艳”!本文就带您一起进入Java的“水晶之恋”。

 

二、立体水晶效果

受苹果公司的影响,现在立体水晶风格的界面非常流行。Java也可以吗?我们不妨先尝试一下用Java绘制一个立体水晶风格的按钮到底有多难。一个立体的水晶按钮应当有一个图标、一个圆角矩形区域、边框以及一些立体反光效果,如下图:

 

简单思路如下:先画矩形区域,然后画图标,然后设置clip并画高亮反光区域,最后画外部边框。

具体实现比较简单,主要代码如下:

Color color = TWaverUtil.getRandomColor(); 
 RoundRectangle2D body 
= new RoundRectangle2D.Float(x, y, size, size, size / 3, size / 3
); 

//draw body 

g2d.setColor(color); 
GradientPaint paint 
= new
 GradientPaint(x, 
                    y, 
                    color.darker(), 
                    x, 
                    y 
+
 size, 
                    color.brighter().brighter()); 
g2d.setPaint(paint); 
g2d.fill(body); 

//draw image 

g2d.setClip(body); 
Image image 
= TWaverUtil.getImage("/glass/" + i + ".png"
); 
g2d.drawImage(image, 
               x 
+ (size - image.getWidth(null)) / 2

               y 
+ (size - image.getHeight(null)) / 2

               
null
); 
g2d.setClip(
null
); 

//draw highlight. 

Shape highlightArea = createHighlightShape(x, y, size, body); 
g2d.setColor(
new Color(255255255150
)); 
g2d.fill(highlightArea); 

//draw outline. 

g2d.setColor(color.darkGray); 
g2d.draw(body);

其中,对高亮区域的计算,可以用一个圆心在左上方的大圆形和矩形进行剪切:
private static Shape createHighlightShape(int centerX, int centerY, int size, Shape body) { 
double myRadius = size * 4

  
double x = centerX - size * 2.3

  
double y = centerY - size * 3.2

  Ellipse2D.Double circle 
= new
 Ellipse2D.Double(x, y, myRadius, myRadius); 
  Area area 
= new
 Area(circle); 
  area.intersect(
new
 Area(body)); 
  
return
 area; 
}
 

运行程序效果如下:

 


三、更多变化

根据上面例子稍作形状变换,可以画出立体水晶球的按钮。
Color color = TWaverUtil.getRandomColor(); 

Ellipse2D.Double circle 
= new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2
); 

//draw body 

g2d.setColor(color); 
GradientPaint paint 
= new GradientPaint(centerX, centerY, color, centerX, centerY + radius * 2
, color.brighter().brighter()); 
g2d.setPaint(paint); 
g2d.fill(circle); 

//draw image 

g2d.setClip(circle); 
Image image 
= TWaverUtil.getImage("/glass/" + i + ".png"
); 
g2d.drawImage(image, 
centerX 
- image.getWidth(null/ 2

                 centerY 
- image.getHeight(null/ 2

                 
null
); 
g2d.setClip(
null
); 

//draw highlight. 

Shape highlightArea = createHighlightShape(centerX, centerY, radius); 
g2d.setColor(
new Color(255255255150
)); 
g2d.fill(highlightArea);

唯一略有不同的部分是,水晶球的高亮区域要用两个圆形拼切:

private static Shape createHighlightShape(int centerX, int centerY, int radius) { 
double myRadius = radius * 0.8

  
double x = centerX -
 myRadius; 
  
double y1 = centerY - myRadius - myRadius / 5

  
double y2 = centerY - myRadius - myRadius / 5 * 2


  Ellipse2D.Double circle1 
= new Ellipse2D.Double(x, y1, myRadius * 2, myRadius * 2
); 
  Ellipse2D.Double circle2 
= new Ellipse2D.Double(x, y2, myRadius * 2, myRadius * 2
); 

  Area area 
= new
 Area(circle1); 
  area.intersect(
new
 Area(circle2)); 
  
return
 area; 
}
 

运行效果如下:


如果再来点儿循环、随机大小、随机位置、随机颜色,就可以做出绚丽的“吹肥皂泡”的效果


 

四、融入Swing组件

以上例子仅使用了Java2D进行绘图。在实际使用中,需要将这些效果应用的Swing组件中,例如按钮等。一个简单的方式是:将以上图形效果在内存中生成内存图片并封装到一个ImageIcon中,然后将ImageIcon图标作为JButton的图标进行显示。

public static Image createImageIcon(Image phantom, int size) {
BufferedImage bi 
= new
 BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
  Graphics2D g2d 
=
 bi.createGraphics();
  g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

  
int center = size / 2
;
  
int radius =
 center;

  
//此处进行画图


  g2d.dispose();
  
return bi;
}
 

然后,用这些Icon创建一些按钮并显示:

public static void main(String[] args) throws Exception {
JFrame frame 
= new
 JFrame();
  frame.getContentPane().setLayout(
new
 FlowLayout());
  frame.getContentPane().add(
new JButton("按钮1"new ImageIcon(createImageIcon(null60
))));
  frame.getContentPane().add(
new JButton("按钮2"new ImageIcon(createImageIcon(null60
))));
  frame.getContentPane().add(
new JButton("按钮3"new ImageIcon(createImageIcon(null60
))));
  frame.getContentPane().add(
new JButton("使用Java2D创建的立体水晶风格的按钮"new ImageIcon(createImageIcon(null30
))));
  frame.setSize(
500300
);
  frame.setTitle(
"Java也惊艳"
);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  TWaverUtil.centerWindow(frame);
  frame.setVisible(
true
);
}

   

效果如下图:

本例子没有使用Look And Feel。你也可以使用JGoodies来美化一下,效果肯定更好。

五、总结

可以看出,画出这类立体水晶效果并不难,只需仔细观察这些效果的光学细节,并用Java2DAPI来实现即可。这些例子稍作改进,就可以用来绘制JButtonSwing组件,并用在实际项目中。或者,也可以应用这些技巧来做一些复杂图形界面,如在TWaver中做出的网络拓扑图效果:

 

本文知识要点:

n         渐变填充:这个使用GradientPaint就行了;

n         使用Clip:类似蒙版/剪切的Java2D技术。看看GraphicssetClip函数就明白了;

n         Area的使用:主要是Area的相交、合并等几个常见图形处理手法。详细请看java.awt.geom.Area类;

n         生成内存图片:主要是BufferedImage类的使用;

如果大家感兴趣,可以尝试用上述Java2D技巧实现下图效果:

以上内容转载请注明
 

六、参考资料

http://java.sun.com/j2se/1.4.2/docs/guide/2d/spec/j2d-bookTOC.html

http://java.sun.com/j2se/1.4.2/docs/guide/2d/spec.html

http://www.apl.jhu.edu/~hall/java/Java2D-Tutorial.html