构建不规则窗体

在开发一个新浪微博客Swing户端的过程中希望能展现不规则的窗体界面,原来JDK 6 update 10提供了创建指定形状窗体的特性,简单易用,记于此处。(2010.05.31最后更新)

Java从JDK 6 update 10开 始将内建支持构建指定形状的窗体,类com.sun.awt.AWTUtilities中的方法setWindowShape会根据不同的Shape实现 去构造相应形状的窗体。AWTUtilities类是放在SUN的包中,在使用该方法时应该通过反射去进行调用,如下代码所示,
Class <?>  clazz  =  Class.forName( " com.sun.awt.AWTUtilities " );
Method method 
=  clazz.getMethod( " setWindowShape " , Window. class , Shape. class );


1. 创建正常窗体
先创建一个简单的界面,它使用BorderLayout,在其中安放5个JButton,如下代码所示,

public   class  ShapedFrame  extends  JFrame {

    
private   static   final   long  serialVersionUID  =   - 2291343874280454383L ;

    
private  JButton centerButton  =   new  JButton( " Center " );

    
public  ShapedFrame() {
        
super ( " Shaped Frame " );
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        initUI();
    }

    
private   void  initUI() {
        Container container 
=  getContentPane();
        container.setLayout(
new  BorderLayout());

        container.add(
new  JButton( " TOP " ), BorderLayout.PAGE_START);
        container.add(
new  JButton( " RIGHT " ), BorderLayout.LINE_END);
        container.add(
new  JButton( " BOTTOM " ), BorderLayout.PAGE_END);
        container.add(
new  JButton( " LEFT " ), BorderLayout.LINE_START);
        container.add(centerButton, BorderLayout.CENTER);
    }

    
public   static   void  main(String[] args) {
        SwingUtilities.invokeLater(
new  Runnable() {

            @Override
            
public   void  run() {
                ShapedFrame frame 
=   new  ShapedFrame();
                frame.setSize(
new  Dimension( 400 300 ));
                frame.setUndecorated(
true );
                setAtCenter(frame);
                frame.setVisible(
true );
            }
        });
    }

    
//  将Window置于屏幕正中
     private   static   void  setAtCenter(Window window) {
        Dimension screenSize 
=  Toolkit.getDefaultToolkit().getScreenSize();
        window.setLocation((screenSize.width 
-  window.getWidth())  /   2 ,
                (screenSize.height 
-  window.getHeight())  /   2 );
    }
}


执行上述程序的效果如下图所示,


2. 创建不规则窗体
基于上述程序创建不规则窗体,使整个窗体正好缺失掉RIGHT JButton所在的区域,如下代码所示,

public   class  ShapedFrame  extends  JFrame {

    
private   static   final   long  serialVersionUID  =   - 2291343874280454383L ;

    
private   static  Method method  =   null ;

    
static  {
        
try  {
            Class
<?>  clazz  =  Class.forName( " com.sun.awt.AWTUtilities " );
            method 
=  clazz.getMethod( " setWindowShape " , Window. class , Shape. class );
        } 
catch  (Exception e) {
            e.printStackTrace();
        }
    }

    
private  JButton centerButton  =   new  JButton( " Center " );

    
public  ShapedFrame() {
        
super ( " Shaped Frame " );
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        initUI();
        addComponentListener(componentListener);
    }

    
private   void  initUI() {
        Container container 
=  getContentPane();
        container.setLayout(
new  BorderLayout());

        container.add(
new  JButton( " TOP " ), BorderLayout.PAGE_START);
        container.add(
new  JButton( " RIGHT " ), BorderLayout.LINE_END);
        container.add(
new  JButton( " BOTTOM " ), BorderLayout.PAGE_END);
        container.add(
new  JButton( " LEFT " ), BorderLayout.LINE_START);
        container.add(centerButton, BorderLayout.CENTER);
    }

    
private  ComponentListener componentListener  =   new  ComponentAdapter() {

        @Override
        
public   void  componentResized(ComponentEvent evt) { // 当UI组件(JFrame)的尺寸发生改变时,调用该方法
            Rectangle frameRect 
=  getBounds();
            Rectangle spaceRect 
=  centerButton.getBounds();

            Point o1 
=   new  Point( 0 0 );
            Point o2 
=   new  Point(frameRect.width,  0 );
            Point o3 
=   new  Point(frameRect.width, frameRect.height);
            Point o4 
=   new  Point( 0 , frameRect.height);

            Point i1 
=   new  Point(spaceRect.x  +  spaceRect.width, spaceRect.y);
            Point i2 
=   new  Point(frameRect.width, spaceRect.y);
            Point i3 
=   new  Point(frameRect.width, spaceRect.y
                    
+  spaceRect.height);
            Point i4 
=   new  Point(spaceRect.x  +  spaceRect.width, spaceRect.y +  spaceRect.height);

            
int [] xpoints  =   new   int [] { o1.x, o2.x, i2.x, i1.x, i4.x, i3.x, o3.x, o4.x };
            
int [] ypoints  =   new   int [] { o1.y, o2.y, i2.y, i1.y, i4.y, i3.y, o3.y, o4.y };
            
int  npoints  =   8
            // 构建一个六边形,将RIGHT JButton所处的位置空缺出来

            Shape shape 
=   new  Polygon(xpoints, ypoints, npoints);

            setWindowShape(ShapedFrame.
this , shape);
        }
    };

    
//  设置Window的形状
     private   static   void  setWindowShape(Window window, Shape shape) {
        
try  {
            method.invoke(
null , window, shape);
        } 
catch  (Exception e) {
            e.printStackTrace();
        }
    }

    
public   static   void  main(String[] args) {
        SwingUtilities.invokeLater(
new  Runnable() {

            @Override
            
public   void  run() {
                ShapedFrame frame 
=   new  ShapedFrame();
                frame.setSize(
new  Dimension( 400 300 ));
                frame.setUndecorated(
true );
                setAtCenter(frame);
                frame.setVisible(
true );
            }
        });
    }

    
//  将Window置于屏幕正中
     private   static   void  setAtCenter(Window window) {
        Dimension screenSize 
=  Toolkit.getDefaultToolkit().getScreenSize();
        window.setLocation((screenSize.width 
-  window.getWidth())  /   2 ,
                (screenSize.height 
-  window.getHeight())  /   2 );
    }
}


执行上述程序后,会有如下图所示的效果,