2012-04-11 32 views

回答

7

有幾個選項和他們每個人都有自己的優點和缺點...

  1. 創建一個自定義形狀的窗口 - 這種方法有些系統將能夠創造背後的另外的窗簾也可以在大多數系統上工作(即使在Linux JDK上也可以工作)。這種方法的糟糕之處(實際上使其無法使用)是非混淆的形狀邊界線 - 如果您創建了一些橢圓形窗口,則其邊將顯得粗糙。

  2. 用繪製的形狀創建一個不透明的未打孔窗口 - 此方法將解決(1)方法的主要問題。你可以在完全透明的窗口上繪製別名。這一個壞消息是它只能在Win和Mac系統上運行。在(大部分)任何Linux系統上,您將得到一個矩形窗口和大量關於不支持的操作的錯誤。

  3. 在java窗口內部創建一個自定義形狀的彈出窗口,並將其放置在窗口分層或玻璃窗格中。這將允許您完全避免任何兼容性問題並獲得(2)方法的好處。這種方法有一個壞處 - 你只能在窗口的根窗格界限中顯示這樣的彈出窗口。在大多數情況下,這仍然比其他兩種方式好得多,因爲它使用的資源更少,不會創建額外的窗口,並且您可以控制彈出窗口的每個部分。

關於第三個方法 - 你可以檢查的ToolTipManager我有我自己的項目WebLookAndFeel創造的 - 它使用窗玻璃的顯示與陰影效果定製形半透明的工具提示。也很快,我將添加窗口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; 
    } 
} 

1的方法例如:

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中,但具有別名的一面,並且可以在任何類型的操作系統上正常工作。

+0

很好的答案+1 – mKorbel 2012-04-11 06:42:43

+0

我添加的代碼樣本,所有的方法 – 2012-04-11 07:19:21

+0

的我已經注意到這個問題,並改變了文本,但謝謝你的提示:) – 2012-04-11 07:22:23