我找不到合适的布局管理器。我在 JPanel 中有一些图像,它们的大小都不同,所以我想使用流布局让经理处理它们。管理器尽可能填充所有第一行,然后翘曲到另一行。这一切都没关系,但我想要的是停止第二次"扭曲"。我只想显示 2 行图像,如果您想查看更多图像,则必须单击 JButton 以加载其他图像。实际上,FlowLayout一直在第三行中插入,并且由于面板不够"高",图像被削减了一半。有什么提示吗?我已经尝试过流布局和米格布局,但没有成功。
将 FlowLayout(outerPanel) 与 GridBagLayout(innerPannel) 组合在一起您可以自己定义行,然后在其上放置一个JScrollPane,这样它就不会剪切您的图片,并且您仍然可以完整地看到它们(我的建议)
我忍不住试图解决这个问题。 我曾希望使用FlowLayouts,但最终,我只使用了GridBagLayouts:每行图像一个,整个容器一个。 我可能在灵活性方面过度设计,但我想这样的东西将来可能对我自己或其他人有用。
实质上,每次容器更改大小、添加/删除图像或其任何可视属性更改时,都会调用updateLayout()
,从头开始重建所有 GridBagLayout 面板。 我确信有一些方法可以提高效率,并且我确信可以从 scatch 编写一个 LayoutManager2 实现来完成这项工作,但这对我来说表现得相当不错。
import java.util.List;
import java.util.ArrayList;
import java.util.Objects;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ImagePanel
extends JPanel {
private static final long serialVersionUID = 1;
/** @serial */
private final List<Icon> images = new ArrayList<>();
/** @serial */
private final List<Icon> scaledImages = new ArrayList<>();
/** @serial */
private int maxRowCount = 2;
/** @serial */
private int hgap = 6;
/** @serial */
private int vgap = 6;
/** @serial */
private int maxImageWidth = 200;
/** @serial */
private int maxImageHeight = 200;
public ImagePanel() {
setLayout(new GridBagLayout());
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent event) {
updateLayout();
}
});
}
@Override
public void addNotify() {
super.addNotify();
updateLayout();
}
@Override
public Dimension getPreferredSize() {
Rectangle screen = findGraphicsConfiguration().getBounds();
Dimension size = new Dimension();
Dimension row = new Dimension();
int rowsComputed = 0;
int gap = 0;
for (Icon image : scaledImages) {
if (row.width > 0 &&
row.width + gap + image.getIconWidth() > screen.width) {
if (++rowsComputed >= maxRowCount) {
break;
}
size.width = Math.max(size.width, row.width);
size.height += (size.height > 0 ? vgap : 0) + row.height;
row.setSize(0, 0);
gap = 0;
}
row.width += gap + image.getIconWidth();
row.height = Math.max(row.height, image.getIconHeight());
gap = hgap;
}
size.width = Math.max(size.width, row.width);
size.height += (size.height > 0 ? vgap : 0) + row.height;
return size;
}
private void updateLayout() {
int width = getWidth();
if (width == 0) {
return;
}
for (Component rowContainer : getComponents()) {
((JComponent) rowContainer).removeAll();
}
GridBagConstraints rowConstraints = new GridBagConstraints();
rowConstraints.gridwidth = GridBagConstraints.REMAINDER;
rowConstraints.weightx = 1;
rowConstraints.anchor = GridBagConstraints.FIRST_LINE_START;
int row = -1;
int rowWidth = 0;
GridBagConstraints gbc = new GridBagConstraints();
for (Icon image : scaledImages) {
JComponent rowContainer = (row >= 0 && row < getComponentCount() ?
(JComponent) getComponent(row) : null);
int gap = (rowWidth > 0 ? hgap : 0);
if (rowContainer == null ||
rowWidth + gap + image.getIconWidth() > width) {
if (++row >= maxRowCount) {
break;
}
gap = 0;
rowWidth = 0;
if (row < getComponentCount()) {
rowContainer = (JComponent) getComponent(row);
} else {
rowContainer = new JPanel(new GridBagLayout());
add(rowContainer, rowConstraints);
}
rowConstraints.insets.top = vgap;
}
gbc.insets.left = gap;
JComponent imageContainer = new JLabel(image);
rowContainer.add(imageContainer, gbc);
rowWidth += gap + image.getIconWidth();
}
for (int i = getComponentCount() - 1; i >= maxRowCount; i--) {
remove(i);
}
}
private GraphicsConfiguration findGraphicsConfiguration() {
GraphicsConfiguration config = getGraphicsConfiguration();
if (config == null) {
GraphicsEnvironment env =
GraphicsEnvironment.getLocalGraphicsEnvironment();
config = env.getDefaultScreenDevice().getDefaultConfiguration();
}
return config;
}
private Icon scale(Icon image) {
int imageWidth = image.getIconWidth();
int imageHeight = image.getIconHeight();
if (imageWidth > maxImageWidth || imageHeight > maxImageHeight) {
float scale = Math.min((float) maxImageWidth / imageWidth,
(float) maxImageHeight / imageHeight);
if (scale < 1) {
GraphicsConfiguration config = findGraphicsConfiguration();
BufferedImage scaledImage = config.createCompatibleImage(
(int) (imageWidth * scale),
(int) (imageHeight * scale));
Graphics2D g = scaledImage.createGraphics();
g.scale(scale, scale);
image.paintIcon(this, g, 0, 0);
g.dispose();
image = new ImageIcon(scaledImage);
}
}
return image;
}
public List<Icon> getImages() {
return new ArrayList<>(images);
}
public void clearImages() {
images.clear();
updateLayout();
revalidate();
}
public void addImage(Icon image) {
Objects.requireNonNull(image, "Image cannot be null");
images.add(image);
scaledImages.add(scale(image));
updateLayout();
revalidate();
}
public void removeImage(Icon image) {
int index = images.indexOf(image);
if (index >= 0) {
removeImage(index);
}
}
public void removeImage(int index) {
images.remove(index);
scaledImages.remove(index);
updateLayout();
revalidate();
}
public int getHgap() {
return hgap;
}
public void setHgap(int gap) {
if (gap < 0) {
throw new IllegalArgumentException("Gap must be at least zero");
}
int old = this.hgap;
this.hgap = gap;
if (old != gap) {
updateLayout();
revalidate();
}
firePropertyChange("hgap", old, gap);
}
public int getVgap() {
return vgap;
}
public void setVgap(int gap) {
if (gap < 0) {
throw new IllegalArgumentException("Gap must be at least zero");
}
int old = this.vgap;
this.vgap = gap;
if (old != gap) {
updateLayout();
revalidate();
}
firePropertyChange("vgap", old, gap);
}
public int getMaxRowCount() {
return maxRowCount;
}
public void setMaxRowCount(int count) {
if (count < 0) {
throw new IllegalArgumentException("Count must be at least zero");
}
int old = this.maxRowCount;
this.maxRowCount = count;
if (old != count) {
updateLayout();
revalidate();
}
firePropertyChange("maxRowCount", old, count);
}
public int getMaxImageWidth() {
return maxImageWidth;
}
private void recomputeScaledImages() {
scaledImages.clear();
for (Icon image : images) {
scaledImages.add(scale(image));
}
}
public void setMaxImageWidth(int width) {
if (width <= 0) {
throw new IllegalArgumentException("Width must be positive");
}
int old = this.maxImageWidth;
this.maxImageWidth = width;
if (old != width) {
recomputeScaledImages();
updateLayout();
revalidate();
}
firePropertyChange("maxImageWidth", old, width);
}
public int getMaxImageHeight() {
return maxImageHeight;
}
public void setMaxImageHeight(int height) {
if (height <= 0) {
throw new IllegalArgumentException("Height must be positive");
}
int old = this.maxImageHeight;
this.maxImageHeight = height;
if (old != height) {
recomputeScaledImages();
updateLayout();
revalidate();
}
firePropertyChange("maxImageHeight", old, height);
}
public static void main(final String[] args)
throws java.io.IOException {
if (args.length == 0) {
System.err.println("Usage: java " + ImagePanel.class.getName()
+ " <directory> | <url1> <url2> ...");
System.exit(2);
}
final List<java.net.URL> urls;
if (args.length == 1 && !args[0].contains(":")) {
urls = new ArrayList<>();
try (java.nio.file.DirectoryStream<java.nio.file.Path> dir =
java.nio.file.Files.newDirectoryStream(
java.nio.file.Paths.get(args[0]))) {
for (java.nio.file.Path file : dir) {
urls.add(file.toUri().toURL());
}
}
} else {
urls = new ArrayList<>(args.length);
for (String url : args) {
urls.add(new java.net.URL(url));
}
}
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
ImagePanel imagePanel = new ImagePanel();
for (java.net.URL url : urls) {
imagePanel.addImage(new ImageIcon(url));
}
javax.swing.JFrame frame =
new javax.swing.JFrame("ImagePanel");
frame.setDefaultCloseOperation(
javax.swing.JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.weightx = 1;
gbc.weighty = 1;
panel.add(imagePanel, gbc);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
}