두 개의 별도 JPanels (또는 모든 경량 구성 요소)가 서로 위에 있고 궁극적으로 JPanel 내에 포함되거나 JLayeredPane과 같은 것을 통해 필요합니다. 따라서 중량이 큰 구성 요소 나 유리 패널이 없습니다. 배경 JPanel (BackgroundPanel)은 배경 이미지를 페인트하거나 화면 비율을 유지하면서 알파를 사용하면서 비디오를 재생합니다. 상단 패널 (CompassPanel)에는 아이콘이 있으며 아이콘을 추가하고 삭제하고 다이어그램 라이브러리와 같이 이동할 수 있습니다 (이 기능은이 게시물과 직접 관련이 없습니다). 내 JNLP 앱 및 배포 환경에서 대역폭 제약으로 인해 많은 외부 종속성을 추가 할 수 없습니다. 그러나 배경 이미지와 비디오를 유지하는 알파 & 종횡비를 처리 할 수있는 경량 다이어그램 라이브러리를 아는 사람은 게임입니다. 이 공간은 크기 조정 후 할당하는 이유 그렇지 않으면, 나는 내 인생 알아낼 수 없기 : 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);
}
}
난 그냥 BackgroundPanel #의 paintComponent의 그래픽 구성 요소가 다른 "클립 경계"가 나타났습니다 예상 한 것보다 JLayerPane보다 작습니다. 나는 왜 그런지 모르지만 paintComponent는 내가 생각한 것의 서브셋만을 그리는 것처럼 보입니다. –
'paintComponent'는 화면을 갱신 할 필요가 있다고 생각하는 부분 만 칠해서 페인트 칠을 시도합니다. 이 정보를 사용하여 특히 복잡한 페인트가있는 경우 구성 요소의 특정 부분을 페인트해야하는지 결정할 수 있습니다. 자세한 내용은 [AWT 및 스윙의 페인팅] (http://www.oracle.com/technetwork/java/painting-140037.html)을 참조하십시오. – MadProgrammer
내가 읽은 것부터 좋은 선택을하는 것처럼 보입니다. 목표를 달성하는쪽으로 – MadProgrammer