2012-04-11 38 views
5

Tôi muốn tạo cửa sổ bật lên theo yêu thích của Google Chrome bằng mũi tên, các góc được làm tròn và nếu tôi có thời gian hiệu ứng đổ bóng. Trong Java Swing. Đâu là cách tiếp cận lí tưởng nhất? SplashScreen? Hoặc chỉ đơn giản là AWT Window? Những ý tưởng khác? Cảm ơn!Swing: popover với mũi tên

Trả lời

7

Có một vài lựa chọn và mỗi người trong số họ có ưu và nhược điểm riêng của mình ...

  1. Tạo một cửa sổ tùy chỉnh hình - với phương pháp này một số hệ thống sẽ có thể tạo thêm bóng mát phía sau hình cửa sổ, cũng điều này hoạt động trên hầu hết các hệ thống (nên làm việc ngay cả trên linux của JDK). Điều xấu về cách tiếp cận này (thực sự làm cho nó không sử dụng được) là đường biên giới hình dạng không thiên vị - nếu bạn tạo ra một số cửa sổ hình elip các cạnh của nó sẽ xuất hiện thô.

  2. Tạo cửa sổ chưa được đục lỗ chưa được đục với hình vẽ - cách tiếp cận này sẽ khắc phục vấn đề chính của phương pháp (1). Bạn có thể tạo hình dạng bí danh bạn vẽ trên cửa sổ trong suốt hoàn toàn. Điều xấu về điều này là nó chỉ hoạt động trên các hệ thống Win và Mac. Trên (chủ yếu) bất kỳ hệ thống Linux, bạn sẽ nhận được một cửa sổ hình chữ nhật kết quả và tấn lỗi về các hoạt động không được hỗ trợ.

  3. Tạo cửa sổ bật lên có hình tùy chỉnh bên trong cửa sổ java và đặt cửa sổ lên lớp cửa sổ hoặc ngăn kính. Điều này sẽ cho phép bạn tránh hoàn toàn bất kỳ vấn đề tương thích nào và nhận được lợi ích của phương pháp (2). Có một điều xấu về cách tiếp cận này mặc dù - bạn chỉ có thể hiển thị popup như vậy trong khung cửa sổ gốc gốc. Điều này vẫn tốt hơn nhiều so với hai cách khác trong hầu hết các trường hợp, vì nó sử dụng ít tài nguyên hơn, không tạo thêm cửa sổ và bạn có thể kiểm soát mọi phần của cửa sổ bật lên.

Về cách tiếp cận thứ 3 - bạn có thể kiểm tra TooltipManager tôi đã tạo ra trong dự án của riêng tôi WebLookAndFeel - nó sử dụng khung kính cửa sổ để hiển thị tùy chỉnh hình tooltips bán trong suốt với một cái bóng-có hiệu lực. Cũng đủ sớm, tôi sẽ thêm cửa sổ PopupManager cho phép tạo nhanh các cửa sổ bật lên "bên trong".

Dưới đây là một số ví dụ về các cách tiếp cận:

Một chút mã mà sử dụng trước trong tất cả các ví dụ

Phương pháp để tạo ra hình dạng:

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; 
} 

Chuột bộ chuyển đổi cho phép để di chuyển cửa sổ bằng cách kéo thành phần:

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; 
    } 
} 

cách tiếp cận 1 ví dụ:

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); 
} 

Như bạn có thể nhìn thấy - góc của hình tròn là khá thô và không đẹp

cách tiếp cận thứ 2:

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); 
} 

Bây giờ nó sẽ trông hoàn hảo - vấn đề duy nhất này sẽ chỉ hoạt động tốt trên Windows và Mac (ít nhất là trong 1.6.x JDK). Atleast nó đã được như vậy về một tháng trước khi tôi lần cuối cùng kiểm tra nó trên hệ điều hành khác nhau.

cách tiếp cận thứ 3

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); 
} 

Đây là một ví dụ đơn giản của popup đặt trên kính cửa sổ. Như bạn có thể thấy nó chỉ tồn tại bên trong JFrame, nhưng có mặt bí danh và hoạt động đúng trên bất kỳ loại hệ điều hành nào.

+0

câu trả lời rất tốt 1 – mKorbel

+0

Tôi đã thêm các mẫu mã cho tất cả các phương pháp tiếp cận –

+0

Tôi đã nhận thấy vấn đề và thay đổi văn bản, nhưng thanks for the tip :) –

Các vấn đề liên quan