Java Swing 垂直流布局管理器实现


最近写一个java UI,需要用到垂直流布局管理器,要求该管理器能够实现内部组件的宽度自适应。看了swing提供的5个布局管理器,尝试的实现效果都不理想,看来只能自己搞一个了,好在网上已有实现,其测试效果如下图:

图一 垂直流布局管理器实现效果

具体代码如下:

清单一:

  1. import java.awt.Component;  
  2. import java.awt.Container;  
  3. import java.awt.Dimension;  
  4. import java.awt.FlowLayout;  
  5. import java.awt.Insets;  
  6.   
  7. import javax.swing.JButton;  
  8. import javax.swing.JFrame;  
  9.   
  10. /** 
  11.  * VerticalFlowLayout is similar to FlowLayout except it lays out components 
  12.  * vertically. Extends FlowLayout because it mimics much of the behavior of the 
  13.  * FlowLayout class, except vertically. An additional feature is that you can 
  14.  * specify a fill to edge flag, which causes the VerticalFlowLayout manager to 
  15.  * resize all components to expand to the column width Warning: This causes 
  16.  * problems when the main panel has less space that it needs and it seems to 
  17.  * prohibit multi-column output. Additionally there is a vertical fill flag, 
  18.  * which fills the last component to the remaining height of the container. 
  19.  */  
  20. public class VFlowLayout extends FlowLayout  
  21. {  
  22.     /** 
  23.      *  
  24.      */  
  25.     private static final long serialVersionUID = 1L;  
  26.   
  27.     /** 
  28.      * Specify alignment top. 
  29.      */  
  30.     public static final int TOP = 0;  
  31.   
  32.     /** 
  33.      * Specify a middle alignment. 
  34.      */  
  35.     public static final int MIDDLE = 1;  
  36.   
  37.     /** 
  38.      * Specify the alignment to be bottom. 
  39.      */  
  40.     public static final int BOTTOM = 2;  
  41.   
  42.     int hgap;  
  43.     int vgap;  
  44.     boolean hfill;  
  45.     boolean vfill;  
  46.   
  47.     public static void main(String[] args)  
  48.     {  
  49.         System.out.println("Just for test ...");  
  50.         JFrame frame = new JFrame();  
  51.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  52.         frame.setBounds(00600600);  
  53.         frame.setLayout(new VFlowLayout());  
  54.           
  55.         int i = 0;  
  56.         frame.add(new JButton(String.valueOf(i++)));  
  57.         frame.add(new JButton(String.valueOf(i++)));  
  58.         frame.add(new JButton(String.valueOf(i++)));  
  59.         frame.add(new JButton(String.valueOf(i++)));  
  60.         frame.add(new JButton(String.valueOf(i++)));  
  61.         frame.add(new JButton(String.valueOf(i++)));  
  62.         frame.add(new JButton(String.valueOf(i++)));  
  63.         frame.add(new JButton(String.valueOf(i++)));  
  64.         frame.add(new JButton(String.valueOf(i++)));  
  65.         frame.add(new JButton(String.valueOf(i++)));  
  66.         frame.add(new JButton(String.valueOf(i++)));  
  67.           
  68.         frame.setVisible(true);  
  69.     }  
  70.       
  71.     /** 
  72.      * Construct a new VerticalFlowLayout with a middle alignment, and the fill 
  73.      * to edge flag set. 
  74.      */  
  75.     public VFlowLayout()  
  76.     {  
  77.         this(TOP, 55truefalse);  
  78.     }  
  79.   
  80.     /** 
  81.      * Construct a new VerticalFlowLayout with a middle alignment. 
  82.      *  
  83.      * @param hfill 
  84.      *            the fill to edge flag 
  85.      * @param vfill 
  86.      *            the vertical fill in pixels. 
  87.      */  
  88.     public VFlowLayout(boolean hfill, boolean vfill)  
  89.     {  
  90.         this(TOP, 55, hfill, vfill);  
  91.     }  
  92.   
  93.     /** 
  94.      * Construct a new VerticalFlowLayout with a middle alignment. 
  95.      *  
  96.      * @param align 
  97.      *            the alignment value 
  98.      */  
  99.     public VFlowLayout(int align)  
  100.     {  
  101.         this(align, 55truefalse);  
  102.     }  
  103.   
  104.     /** 
  105.      * Construct a new VerticalFlowLayout. 
  106.      *  
  107.      * @param align 
  108.      *            the alignment value 
  109.      * @param hfill 
  110.      *            the horizontalfill in pixels. 
  111.      * @param vfill 
  112.      *            the vertical fill in pixels. 
  113.      */  
  114.     public VFlowLayout(int align, boolean hfill, boolean vfill)  
  115.     {  
  116.         this(align, 55, hfill, vfill);  
  117.     }  
  118.   
  119.     /** 
  120.      * Construct a new VerticalFlowLayout. 
  121.      *  
  122.      * @param align 
  123.      *            the alignment value 
  124.      * @param hgap 
  125.      *            the horizontal gap variable 
  126.      * @param vgap 
  127.      *            the vertical gap variable 
  128.      * @param hfill 
  129.      *            the fill to edge flag 
  130.      * @param vfill 
  131.      *            true if the panel should vertically fill. 
  132.      */  
  133.     public VFlowLayout(int align, int hgap, int vgap, boolean hfill, boolean vfill)  
  134.     {  
  135.         setAlignment(align);  
  136.         this.hgap = hgap;  
  137.         this.vgap = vgap;  
  138.         this.hfill = hfill;  
  139.         this.vfill = vfill;  
  140.     }  
  141.   
  142.     /** 
  143.      * Returns the preferred dimensions given the components in the target 
  144.      * container. 
  145.      *  
  146.      * @param target 
  147.      *            the component to lay out 
  148.      */  
  149.     public Dimension preferredLayoutSize(Container target)  
  150.     {  
  151.         Dimension tarsiz = new Dimension(00);  
  152.   
  153.         for (int i = 0; i < target.getComponentCount(); i++)  
  154.         {  
  155.             Component m = target.getComponent(i);  
  156.               
  157.             if (m.isVisible())  
  158.             {  
  159.                 Dimension d = m.getPreferredSize();  
  160.                 tarsiz.width = Math.max(tarsiz.width, d.width);  
  161.                   
  162.                 if (i > 0)  
  163.                 {  
  164.                     tarsiz.height += hgap;  
  165.                 }  
  166.                   
  167.                 tarsiz.height += d.height;  
  168.             }  
  169.         }  
  170.           
  171.         Insets insets = target.getInsets();  
  172.         tarsiz.width += insets.left + insets.right + hgap * 2;  
  173.         tarsiz.height += insets.top + insets.bottom + vgap * 2;  
  174.           
  175.         return tarsiz;  
  176.     }  
  177.   
  178.     /** 
  179.      * Returns the minimum size needed to layout the target container. 
  180.      *  
  181.      * @param target 
  182.      *            the component to lay out. 
  183.      * @return the minimum layout dimension. 
  184.      */  
  185.     public Dimension minimumLayoutSize(Container target)  
  186.     {  
  187.         Dimension tarsiz = new Dimension(00);  
  188.   
  189.         for (int i = 0; i < target.getComponentCount(); i++)  
  190.         {  
  191.             Component m = target.getComponent(i);  
  192.               
  193.             if (m.isVisible())  
  194.             {  
  195.                 Dimension d = m.getMinimumSize();  
  196.                 tarsiz.width = Math.max(tarsiz.width, d.width);  
  197.                   
  198.                 if (i > 0)   
  199.                 {  
  200.                     tarsiz.height += vgap;  
  201.                 }  
  202.                   
  203.                 tarsiz.height += d.height;  
  204.             }  
  205.         }  
  206.           
  207.         Insets insets = target.getInsets();  
  208.         tarsiz.width += insets.left + insets.right + hgap * 2;  
  209.         tarsiz.height += insets.top + insets.bottom + vgap * 2;  
  210.           
  211.         return tarsiz;  
  212.     }  
  213.   
  214.     /** 
  215.      * Set true to fill vertically. 
  216.      *  
  217.      * @param vfill 
  218.      *            true to fill vertically. 
  219.      */  
  220.     public void setVerticalFill(boolean vfill)  
  221.     {  
  222.         this.vfill = vfill;  
  223.     }  
  224.   
  225.     /** 
  226.      * Returns true if the layout vertically fills. 
  227.      *  
  228.      * @return true if vertically fills the layout using the specified. 
  229.      */  
  230.     public boolean getVerticalFill()  
  231.     {  
  232.         return vfill;  
  233.     }  
  234.   
  235.     /** 
  236.      * Set to true to enable horizontally fill. 
  237.      *  
  238.      * @param hfill 
  239.      *            true to fill horizontally. 
  240.      */  
  241.     public void setHorizontalFill(boolean hfill)  
  242.     {  
  243.         this.hfill = hfill;  
  244.     }  
  245.   
  246.     /** 
  247.      * Returns true if the layout horizontally fills. 
  248.      *  
  249.      * @return true if horizontally fills. 
  250.      */  
  251.     public boolean getHorizontalFill()  
  252.     {  
  253.         return hfill;  
  254.     }  
  255.   
  256.     /** 
  257.      * places the components defined by first to last within the target 
  258.      * container using the bounds box defined. 
  259.      *  
  260.      * @param target 
  261.      *            the container. 
  262.      * @param x 
  263.      *            the x coordinate of the area. 
  264.      * @param y 
  265.      *            the y coordinate of the area. 
  266.      * @param width 
  267.      *            the width of the area. 
  268.      * @param height 
  269.      *            the height of the area. 
  270.      * @param first 
  271.      *            the first component of the container to place. 
  272.      * @param last 
  273.      *            the last component of the container to place. 
  274.      */  
  275.     private void placethem(Container target, int x, int y, int width, int height, int first, int last)  
  276.     {  
  277.         int align = getAlignment();  
  278.           
  279.         if (align == MIDDLE)  
  280.         {  
  281.             y += height / 2;  
  282.         }  
  283.           
  284.         if (align == BOTTOM)  
  285.         {  
  286.             y += height;  
  287.         }  
  288.           
  289.         for (int i = first; i < last; i++)  
  290.         {  
  291.             Component m = target.getComponent(i);  
  292.             Dimension md = m.getSize();  
  293.               
  294.             if (m.isVisible())  
  295.             {  
  296.                 int px = x + (width - md.width) / 2;  
  297.                 m.setLocation(px, y);  
  298.                 y += vgap + md.height;  
  299.             }  
  300.         }  
  301.     }  
  302.   
  303.     /** 
  304.      * Lays out the container. 
  305.      *  
  306.      * @param target 
  307.      *            the container to lay out. 
  308.      */  
  309.     public void layoutContainer(Container target)  
  310.     {  
  311.         Insets insets = target.getInsets();  
  312.         int maxheight = target.getSize().height - (insets.top + insets.bottom + vgap * 2);  
  313.         int maxwidth = target.getSize().width - (insets.left + insets.right + hgap * 2);  
  314.         int numcomp = target.getComponentCount();  
  315.         int x = insets.left + hgap, y = 0;  
  316.         int colw = 0, start = 0;  
  317.   
  318.         for (int i = 0; i < numcomp; i++)  
  319.         {  
  320.             Component m = target.getComponent(i);  
  321.               
  322.             if (m.isVisible())   
  323.             {  
  324.                 Dimension d = m.getPreferredSize();  
  325.                   
  326.                 // fit last component to remaining height   
  327.                 if ((this.vfill) && (i == (numcomp - 1)))   
  328.                 {  
  329.                     d.height = Math.max((maxheight - y), m.getPreferredSize().height);  
  330.                 }  
  331.   
  332.                 // fit component size to container width   
  333.                 if (this.hfill)  
  334.                 {  
  335.                     m.setSize(maxwidth, d.height);  
  336.                     d.width = maxwidth;  
  337.                 }   
  338.                 else  
  339.                 {  
  340.                     m.setSize(d.width, d.height);  
  341.                 }  
  342.   
  343.                 if (y + d.height > maxheight)  
  344.                 {  
  345.                     placethem(target, x, insets.top + vgap, colw, maxheight - y, start, i);  
  346.                     y = d.height;  
  347.                     x += hgap + colw;  
  348.                     colw = d.width;  
  349.                     start = i;  
  350.                 }   
  351.                 else  
  352.                 {  
  353.                     if (y > 0)  
  354.                     {  
  355.                         y += vgap;  
  356.                     }  
  357.                       
  358.                     y += d.height;  
  359.                     colw = Math.max(colw, d.width);  
  360.                 }  
  361.             }  
  362.         }  
  363.           
  364.         placethem(target, x, insets.top + vgap, colw, maxheight - y, start, numcomp);  
  365.     }  
  366. }  

相关内容