2012-04-11 14 views

Odpowiedz

7

Istnieje kilka opcji, a każdy z nich ma swoje wady i zalety ...

  1. Tworzenie okna niestandardowy kształt - z takim podejściem niektóre systemy będą w stanie stworzyć dodatkowy odcień tył w kształcie okna, działa to również na większość systemów (powinno działać nawet na JDK-a Linuksa). Złą rzeczą w tym podejściu (które w rzeczywistości czyni go bezużytecznym) jest nieregularna linia graniczna kształtu - jeśli utworzysz okno w kształcie elipsy, jego boki będą wyglądać na szorstkie.

  2. Utwórz nieprzezroczyste, nierozwinięte okno z narysowanym kształtem - to podejście rozwiąże główny problem podejścia (1). Możesz kształtować alias, rysując na całkowicie przezroczystym oknie. Złe jest to, że działa tylko na systemach Win i Mac. Na (przeważnie) dowolnym systemie linux dostaniesz prostokąt wynikowy okna i mnóstwo błędów o nieobsługiwanych operacjach.

  3. Utwórz niestandardowe wyskakujące okienko wewnątrz okna java i umieść je na szybach z warstwami lub szybami. Pozwoli to w pełni uniknąć problemów ze zgodnością i uzyskać korzyści z (2) podejścia. Jest jednak coś złego w tym podejściu - możesz wyświetlać tylko takie wyskakujące okienka w oknach okna głównego. W większości przypadków jest to o wiele lepsze niż dwa inne sposoby, ponieważ używa mniej zasobów, nie tworzy dodatkowych okien i można kontrolować każdą część popup.

O 3 podejścia - można sprawdzić TooltipManager stworzyłem w moim projekcie WebLookAndFeel - używa szybę okna do wyświetlania niestandardowych kształtach półprzezroczystych podpowiedzi z cienia efektu. Wkrótce dodam okno PopupManager, które pozwoli na szybkie tworzenie "wewnętrznych" okien popupów.

Oto kilka przykładów rozwiązań:

Trochę kodu użytego do przodu we wszystkich przykładach

Metoda, aby utworzyć kształt:

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

adapter myszy, która umożliwia Aby przenieść okno, przeciągając komponent:

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-ty przykład podejście:

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

Jak widać - narożniki zaokrąglonym kształcie są dość szorstkie i nie wyglądające

2-ty podejście:

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

teraz powinien wyglądać perfekcyjnie - jedyny problem, który będzie poprawnie działał tylko na Windowsie i Macu (co najmniej w 1.6.x JDK). Co najmniej około miesiąca temu, kiedy ostatnio sprawdzałem to na różnych systemach operacyjnych.

3-ty podejście

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

Jest to prosty przykład okienko umieszczony w szklanym szyby. Jak widać, istnieje tylko wewnątrz ramki JFrame, ale ma stronę z aliasami i działa poprawnie na każdym systemie operacyjnym.

+0

bardzo dobra odpowiedź +1 – mKorbel

+0

Dodałem próbki kodu do wszystkich podejść –

+0

Już zauważyłem problem i zmieniłem tekst, ale dzięki za podpowiedź :) –

Powiązane problemy