我需要的顶部2个独立JPanels(或任何轻质组分)的每其他最终嵌入一个JPanel内,直接或通过类似一个的JLayeredPane。 因此,没有重量组分或玻璃板。 底部JPanel(名为BackgroundPanel)描绘了一个背景图像或播放视频,同时保持纵横比和使用α。 上面板(称为CompassPanel)上有图标,并允许用户添加图标,删除它们,移动它们(如图表库,这个功能是不是这个职位直接相关的,虽然)。 我不能因为我的JNLP应用和部署环境的带宽限制很多外部依赖性增加。 但是,如果有人知道一个轻量级的图表库,可以处理的α和纵横比维持的背景图像和视频,我的比赛。 否则,我不能为我的生命弄清楚为什么这个空间正在调整大小后分配:
我已阅读JAVA教程上没有布局管理器去(不是我所想要做的,你在哪里!?GBL),但这些缩放需求,并具有图标大小调整期间留在图像的相同部分,等等。我想不出另一种方式来做到这一点。
下面是代码,我使用的Java 1.7。 此外,这是我的第一个计算器,不温柔;-)
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);
}
}