2016-02-25 75 views
0

我无法找到合适的布局管理器。我在JPanel中有一些图像,它们都是不同的大小,所以我想使用流布局来让经理处理它们。经理填写所有第一行,然后翘曲到另一行。这一切都没问题,但我想要的是停在第二个“翘曲”。我只想显示2行图像,如果你想看更多,你必须点击JButton来加载其他图像。实际上,FlowLayout不断插入第三行,因为面板不够“高”,所以图像被切割了一半。有小费吗? 我已经尝试过流布局和Mig布局而没有成功。选择布局管理器 - Java

+0

GridBag是一个很好的我用过的。 – Logan

+0

您必须确定要显示多少个图像,例如,JPanel上的一行和两行中的3个图像,并仅显示该数量。 FlowLayout的工作原理,GridLayout可能会更好看。 –

+0

没有显示溢出组件是不寻常的 - 如果没有任何工作,你可以始终实现自己的LayoutManager – wero

回答

0

将FlowLayout(outerPanel)与GridBagLayout(innerPannel) 结合起来,你可以自己定义行,然后把JScrollPane放在它上面,这样它就不会剪切你的图片,你仍然可以看到它们全部大小(我的建议)

+0

我不确定如果我理解得很好,但实施中的问题是要知道什么时候必须跳到下一行。我不知道图像的大小(之前),所以我无法知道该行何时已满。当然,我可以得到每个图像的宽度,并计算出来。但我正在寻找一个可以为我处理的布局管理器。 –

0

我无法抗拒试图解决这个问题。我曾希望能够使用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); 
      } 
     }); 
    } 
} 
+0

明天早上我会读代码。但我已经尝试了几次,它调整了我的图像,并按照我所看到的填充了网格。所有的图像都是相同的宽度,所以没有必要使用FlowLayout,是否有意?或者是我做错了什么?如果您可以通过邮件与我联系以获取有关代码的更多信息并达到解决方案,我很乐意。 [email protected] –

+0

是的,我正在测试不同大小的图像,所以我添加了maxImageWidth和maxImageHeight属性。除了'getPreferredSize'和'updateLayout'中的循环外,您可以通过删除'scaledImages'字段并删除代码中对它的所有引用来轻松删除它,在这里您可以简单地用'images'替换scaledImages。 – VGR