有几个选项,每个选项都有自己的优点和缺点……
>创建一个自定义形状的窗口 – 通过这种方法,一些系统将能够在成形窗口后面创建额外的阴影,这也适用于大多数系统(甚至可以在Linux JDK上工作).关于这种方法的坏处(实际上使其无法使用)是非混淆的形状边界线 – 如果你创建一个椭圆形的窗口,它的边将显得粗糙.
>创建一个带有绘制形状的非透明未修饰窗口 – 这种方法将解决(1)方法的主要问题.您可以在完全透明的窗口上绘制别名的形状.关于这个的坏处是它只适用于Win和Mac系统.在(大多数)任何Linux系统上,你将获得一个矩形结果窗口和大量关于不支持的操作的错误.
>在java窗口中创建一个自定义形状的弹出窗口,并将其放置在窗口分层或玻璃窗格上.这将使您完全避免任何兼容性问题,并获得(2)方法的好处.但是这种方法有一个坏处 – 你只能在窗口根窗格界限中显示这样的弹出窗口.在大多数情况下,这仍然比其他两种方式要好得多,因为它使用的资源更少,不会创建额外的窗口,您可以控制弹出窗口的每个部分.
关于第3种方法 – 您可以检查我在自己的项目WebLookAndFeel中创建的TooltipManager – 它使用窗口玻璃窗格显示具有阴影效果的自定义形状的半透明工具提示.也很快我将添加窗口PopupManager,允许快速创建“内部”窗口弹出窗口.
以下是这些方法的一些示例:
在所有示例中使用的一些代码
创建形状的方法:
private static Area createShape ()
{
Area shape = new Area ( new RoundRectangle2D.Double ( 0, 20, 500, 200, 20, 20 ) );
GeneralPath gp = new GeneralPath ( GeneralPath.WIND_EVEN_ODD );
gp.moveTo ( 230, 20 );
gp.lineTo ( 250, 0 );
gp.lineTo ( 270, 20 );
gp.closePath ();
shape.add ( new Area ( gp ) );
return shape;
}
允许通过拖动组件移动窗口的鼠标适配器:
public static class WindowMoveAdapter extends MouseAdapter
{
private boolean dragging = false;
private int prevX = -1;
private int prevY = -1;
public WindowMoveAdapter ()
{
super ();
}
public void mousePressed ( MouseEvent e )
{
if ( SwingUtilities.isLeftMouseButton ( e ) )
{
dragging = true;
}
prevX = e.getXOnScreen ();
prevY = e.getYOnScreen ();
}
public void mouseDragged ( MouseEvent e )
{
if ( prevX != -1 && prevY != -1 && dragging )
{
Window w = SwingUtilities.getWindowAncestor ( e.getComponent () );
if ( w != null && w.isShowing () )
{
Rectangle rect = w.getBounds ();
w.setBounds ( rect.x + ( e.getXOnScreen () - prevX ),
rect.y + ( e.getYOnScreen () - prevY ), rect.width, rect.height );
}
}
prevX = e.getXOnScreen ();
prevY = e.getYOnScreen ();
}
public void mouseReleased ( MouseEvent e )
{
dragging = false;
}
}
第一个方法示例:
public static void main ( String[] args )
{
JFrame frame = new JFrame ();
frame.setUndecorated ( true );
JPanel panel = new JPanel ();
panel.setBackground ( Color.BLACK );
WindowMoveAdapter wma = new WindowMoveAdapter ();
panel.addMouseListener ( wma );
panel.addMouseMotionListener ( wma );
frame.getContentPane ().add ( panel );
Area shape = createShape ();
AWTUtilities.setWindowShape ( frame, shape );
frame.setSize ( shape.getBounds ().getSize () );
frame.setLocationRelativeTo ( null );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setVisible ( true );
}
正如你所看到的那样 – 圆形的角落非常粗糙而且不好看
第二种方法:
public static void main ( String[] args )
{
JFrame frame = new JFrame ();
frame.setUndecorated ( true );
final Area shape = createShape ();
JPanel panel = new JPanel ()
{
protected void paintComponent ( Graphics g )
{
super.paintComponent ( g );
Graphics2D g2d = ( Graphics2D ) g;
g2d.setRenderingHint ( RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON );
g2d.setPaint ( Color.BLACK );
g2d.fill ( shape );
}
};
panel.setOpaque ( false );
WindowMoveAdapter wma = new WindowMoveAdapter ();
panel.addMouseListener ( wma );
panel.addMouseMotionListener ( wma );
frame.getContentPane ().add ( panel );
AWTUtilities.setWindowOpaque ( frame, false );
frame.setSize ( shape.getBounds ().getSize () );
frame.setLocationRelativeTo ( null );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setVisible ( true );
}
现在它应该看起来很完美 – 唯一的问题是它只适用于Windows和Mac(至少在1.6.x JDK中).至少一个月前,我上次在各种操作系统上检查过它.
第三种方法
public static void main ( String[] args )
{
JFrame frame = new JFrame ();
JPanel panel = new JPanel ( new BorderLayout () );
panel.setOpaque ( false );
WindowMoveAdapter wma = new WindowMoveAdapter ();
panel.addMouseListener ( wma );
panel.addMouseMotionListener ( wma );
frame.getContentPane ().add ( panel );
panel.add ( new JButton ( "Test" ) );
final Area shape = createShape ();
JPanel glassPane = new JPanel ( null )
{
public boolean contains ( int x, int y )
{
// This is to avoid cursor and mouse-events troubles
return shape.contains ( x, y );
}
};
glassPane.setOpaque ( false );
frame.setGlassPane ( glassPane );
glassPane.setVisible ( true );
JComponent popup = new JComponent ()
{
protected void paintComponent ( Graphics g )
{
super.paintComponent ( g );
Graphics2D g2d = ( Graphics2D ) g;
g2d.setRenderingHint ( RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON );
g2d.setPaint ( Color.BLACK );
g2d.fill ( shape );
}
};
popup.addMouseListener ( new MouseAdapter ()
{
// To block events on the popup
});
glassPane.add ( popup );
popup.setBounds ( shape.getBounds () );
popup.setVisible ( true );
frame.setSize ( 800, 500 );
frame.setLocationRelativeTo ( null );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setVisible ( true );
}
这是放置在玻璃窗格上的弹出窗口的简单示例.正如您所看到的,它仅存在于JFrame内部,但具有别名的一面并且可以在任何类型的操作系统上正常工作.