2016-02-25 82 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