2013-01-31 1 views
1

두 개의 별도 JPanels (또는 모든 경량 구성 요소)가 서로 위에 있고 궁극적으로 JPanel 내에 포함되거나 JLayeredPane과 같은 것을 통해 필요합니다. 따라서 중량이 큰 구성 요소 나 유리 패널이 없습니다. 배경 JPanel (BackgroundPanel)은 배경 이미지를 페인트하거나 화면 비율을 유지하면서 알파를 사용하면서 비디오를 재생합니다. 상단 패널 (CompassPanel)에는 아이콘이 있으며 아이콘을 추가하고 삭제하고 다이어그램 라이브러리와 같이 이동할 수 있습니다 (이 기능은이 게시물과 직접 관련이 없습니다). 내 JNLP 앱 및 배포 환경에서 대역폭 제약으로 인해 많은 외부 종속성을 추가 할 수 없습니다. 그러나 배경 이미지와 비디오를 유지하는 알파 & 종횡비를 처리 할 수있는 경량 다이어그램 라이브러리를 아는 사람은 게임입니다. 이 공간은 크기 조정 후 할당하는 이유 그렇지 않으면, 나는 내 인생 알아낼 수 없기 : JLayeredPane taking up space that BackgroundPanel should draw on"JLayeredPane, background image + "icon"레이어

나는 레이아웃 매니저 (내가하고 싶었던하지 뭔가없이 진행에 JAVA tutorial을 읽고, 당신은 어디에 GBL !?)). 그러나 이러한 크기 조정 요구 사항 및 크기 조정 중에는 이미지의 동일한 부분에 아이콘이 머무르는 등 다른 방법으로는이 작업을 수행 할 수 없습니다.

여기 코드는 Java 1.7입니다. 또한, 이것은 내 첫 stackoverflow, 부드럽게하지 마십시오 ;-)

import java.awt.AlphaComposite; 
import java.awt.Color; 
import java.awt.Composite; 
import java.awt.Cursor; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Image; 
import java.awt.Insets; 
import java.awt.Rectangle; 
import java.awt.event.ComponentAdapter; 
import java.awt.event.ComponentEvent; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.imageio.ImageIO; 
import javax.swing.BorderFactory; 
import javax.swing.ImageIcon; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JLayeredPane; 
import javax.swing.JPanel; 
import javax.swing.border.BevelBorder; 

public class Panel extends JPanel { 

    private static final Logger logger = Logger.getLogger(Panel.class.getName()); 

    public Panel() throws IOException { 

     final BufferedImage backgroundImage = ImageIO.read(new URL(
       "http://www.windpoweringamerica.gov/images/windmaps/us_windmap_80meters_820w.jpg")); 
     final Dimension backgroundImageSize = new Dimension(backgroundImage.getWidth(), backgroundImage.getHeight()); 
     logger.log(Level.INFO, "Image dimensions: {0}", backgroundImageSize); 
     setToolTipText("This is the panel"); 

     final JLayeredPane layeredPane = new JLayeredPane(); 
     layeredPane.setBorder(BorderFactory.createLineBorder(Color.RED, 10)); 
     layeredPane.setToolTipText("This is the layered pane!"); 
     layeredPane.getInsets().set(0, 0, 0, 0); 

     final BackgroundPanel backgroundImagePanel = new BackgroundPanel(backgroundImage); 
     final CompassPanel compassPanel = new CompassPanel(); 
     backgroundImagePanel.setToolTipText("You'll probably never see me, I'm in the background, forever beneath the compass panel"); 
     compassPanel.setToolTipText("I'm the compass panel"); 

     // Per http://docs.oracle.com/javase/tutorial/uiswing/layout/none.html, for every container w/o a layout manager, I must: 
     // 1) Set the container's layout manager to null by calling setLayout(null). -- I do this here 
     // 2) Call the Component class's setbounds method for each of the container's children. --- I do this when resizing 
     // 3) Call the Component class's repaint method. --- I do this when resizing 

     setLayout(null); 
     add(layeredPane); 
     layeredPane.add(backgroundImagePanel, JLayeredPane.DEFAULT_LAYER); 
     layeredPane.add(compassPanel, JLayeredPane.PALETTE_LAYER); 

     // Whenever this panel gets resized, make sure the layered pane gets resized to preserve the aspect ratio of the background image 
     addComponentListener(new ComponentAdapter() { 
      @Override 
      public void componentResized(ComponentEvent evt) { 
       Dimension availableSize = calculateAvailableSize(Panel.this); 
       Rectangle contentBounds = calculateBoundsToFitImage(availableSize, backgroundImageSize); 
       // Ok, this is a big deal. Now I know how big everything has to be, lets force it all to be the right size & repaint. 
       layeredPane.setBounds(contentBounds); 
       backgroundImagePanel.setBounds(contentBounds); 
       compassPanel.setBounds(contentBounds); 

       Panel.this.repaint(); 
       logger.info(String.format("Panel size: %s. Available size: %s. Content Bounds: %s", getSize(), availableSize, contentBounds)); 
      } 
     }); 
    } 

    /** 
    * Paints the constant fitted aspect-ratio background image with an alpha of 0.5 
    */ 
    private static class BackgroundPanel extends JPanel { 

     private static final Logger logger = Logger.getLogger(BackgroundPanel.class.getName()); 
     private final AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f); 
     private final BufferedImage backgroundImage; 

     BackgroundPanel(BufferedImage backgroundImage) { 
      setLayout(null); 
      this.backgroundImage = backgroundImage; 
     } 
     private Dimension lastPaintedDimensions = null; 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      final Dimension size = getSize(); 
      if (lastPaintedDimensions == null || !size.equals(lastPaintedDimensions)) { 
       logger.log(Level.INFO, String.format("Painting background on %d x %d", size.width, size.height)); 
      } 
      final Image paintMe = backgroundImage.getScaledInstance(size.width, size.height, Image.SCALE_SMOOTH); 
      final Graphics2D g2 = (Graphics2D) g.create(); 
      g2.drawImage(paintMe, 0, 0, this); 
      g2.setColor(Color.BLUE); 
      g2.dispose(); 
      lastPaintedDimensions = size; 
     } 
    }; 

    private static class CompassPanel extends JPanel { 

     final List<Compass> compassLabels = new ArrayList<>(); 

     CompassPanel() { 
      setLayout(null); 
      setOpaque(false); 
      setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); 
     } 
    } 

    private static class Compass extends JLabel { 

     private static final BufferedImage compassImage; 

     static { 
      try { 
       compassImage = ImageIO.read(new URL("http://cdn1.iconfinder.com/data/icons/gur-project-1/32/1_7.png")); 
      } catch (IOException ex) { 
       throw new RuntimeException("Failed to read compass image", ex); 
      } 
     } 
     final float xPercent, yPercent; 

     public Compass(float xPercent, float yPercent) { 
      this.xPercent = xPercent; 
      this.yPercent = yPercent; 
      setIcon(new ImageIcon(compassImage)); 
      setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); 
      setOpaque(true); 
      setCursor(Cursor.getDefaultCursor()); 
     } 
    } 

    public static void main(String[] args) throws IOException { 
     final JFrame frame = new JFrame("Hello Stackoverflowwwwwww! Here is a Dynamic Layered Pane Question."); 
     frame.setLayout(null); 
     frame.setContentPane(new Panel()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(800, 600); 
     frame.setVisible(true); 
    } 

    private static Dimension calculateAvailableSize(final JComponent component) { 

     int availableHeight = component.getSize().height; 
     int availableWidth = component.getSize().width; 

     final Insets insets = component.getInsets(); 

     availableHeight -= insets.top; 
     availableHeight -= insets.bottom; 

     availableWidth -= insets.left; 
     availableWidth -= insets.right; 

     if (component.getBorder() != null) { 
      Insets borderInsets = component.getBorder().getBorderInsets(component); 
      if (borderInsets != null) { 
       availableHeight -= borderInsets.top; 
       availableHeight -= borderInsets.bottom; 

       availableWidth -= borderInsets.left; 
       availableWidth -= borderInsets.right; 
      } 
     } 

     return new Dimension(availableWidth, availableHeight); 
    } 

    private static Rectangle calculateBoundsToFitImage(Dimension parentSize, Dimension imageSize) { 
     final double scaleFactor; 
     final int xOffset, yOffset, scaledHeight, scaledWidth; 
     { 
      final double xScaleFactor = (double) parentSize.width/imageSize.width; 
      final double yScaleFactor = (double) parentSize.height/imageSize.height; 
      scaleFactor = xScaleFactor > yScaleFactor ? yScaleFactor : xScaleFactor; 
      scaledHeight = (int) Math.round(scaleFactor * imageSize.height); 
      scaledWidth = (int) Math.round(scaleFactor * imageSize.width); 
     } 

     xOffset = (int) ((parentSize.width - scaledWidth)/2.0); 
     yOffset = (int) ((parentSize.height - scaledHeight)/2.0); 
     return new Rectangle(xOffset, yOffset, scaledWidth, scaledHeight); 
    } 
} 
+0

난 그냥 BackgroundPanel #의 paintComponent의 그래픽 구성 요소가 다른 "클립 경계"가 나타났습니다 예상 한 것보다 JLayerPane보다 작습니다. 나는 왜 그런지 모르지만 paintComponent는 내가 생각한 것의 서브셋만을 그리는 것처럼 보입니다. –

+0

'paintComponent'는 화면을 갱신 할 필요가 있다고 생각하는 부분 만 칠해서 페인트 칠을 시도합니다. 이 정보를 사용하여 특히 복잡한 페인트가있는 경우 구성 요소의 특정 부분을 페인트해야하는지 결정할 수 있습니다. 자세한 내용은 [AWT 및 스윙의 페인팅] (http://www.oracle.com/technetwork/java/painting-140037.html)을 참조하십시오. – MadProgrammer

+0

내가 읽은 것부터 좋은 선택을하는 것처럼 보입니다. 목표를 달성하는쪽으로 – MadProgrammer

답변

1

Doh. 방금 내 질문에 대답했습니다. #setBounds를 호출하면 당신의 부모 컨테이너를 기준으로, 그래서 그 X & Y 오프셋 제대로 설명 할 필요가 있기 (위해) 때문에,이 해결

backgroundImagePanel.setBounds(0, 0, contentBounds.width, contentBounds.height); 
compassPanel.setBounds(0, 0, contentBounds.width, contentBounds.height); 
+0

나는 이것을 개선하는 데 도움이되는 개선 사항이나 라이브러리에 대한 아이디어가 있는지 알고 싶습니다. –

+1

[예제] (http://stackoverflow.com/a/10747783/230513) [tag : jmapviewer]도 참조하십시오. – trashgod

+1

@trashgod 좋아 보인다! 나는 JMF를 사용하여 어떻게 그 레이어 뒤에 영화를 넣을 수 있는지, 아니면 적어도 영화 이미지를 볼 수 있는지 살펴볼 것입니다. 확실하지는 않습니다. 이상한 요구 사항입니다. 내 이미지는 일반적으로지도가 아니며 위의 예에서지도를 사용했습니다. 좋은 도서관, 고마워! –