Java资源网

| JAVA基础 | 环境配置 | JDBC | 线程技术 | Socket编程 | JavaMail | JAVA与XML | 设计模式 | 技术新闻 | Java认证 | 程序人生 软件下载
| JSP&Servlet | Spring | Struts | Hibernate | JBuilder | Eclipse | WebService | EJB技术 | J2ME开发 | 应用服务器 | JXTA | Ajax
Articles search文章搜索
   关键字:
   类 别:
       
New download 最新下载
· [组件]HTML Parser 1.5
· [教程]WebSphere Studio应用教程
· [组件]JDom 1.0
· [工具]Junit3.8.1
· [教程]EJB编程及J2EE系统架构和设计
· [教程]EJB教程
· [教程]J2EE Tutorial中文版
· [教程]Java编程思想2(英文)
· [教程]java编程思想(完整版)
· [教程]Java网络编程
New articles 最新文章
· 设计移动 Web 服务
· 解析XML的时候完全忽略DTD
· 理解XML Schema XML Schema 初步
· 标签库的深入研究
· 提升JSP应用程序的七大绝招
· 如何使用JDOM对XML文件进行操作
· 处理XML字符串中特殊字符
· 利用Digester把XML转换成为Java对象
· 使用WebService 和RMI远程协作
· 使用Axis开发Web Service程序
Articles top 热门文章
· Eclipse基础--plugin插件安装(6644)
· eclipse+tomcat+lomboz的安装配置说明(4774)
· Java程序员就业前景(4584)
· Windows下JAVA环境变量的设置祥解(3788)
· Tomcat下JSP、Servlet和JavaBean环境的配置(3716)
· 使用links方式安装Eclipse插件(3698)
· 一个老程序员的心理话(3533)
· linux下jdk的安装与配置(3459)
· 初学者入门:Structs中基本配置入门(3334)
· Eclipse 运行命令行参数大全(3084)
您的位置:首页>>JAVA基础>>布局管理器LayoutManager
布局管理器LayoutManager
2005-08-25   来源:Java研究组织  作者:javamonkey
LayoutManager 直接子类:GridLayout, FlowLayout等
调用:java.awt.Container调用doLayout时调用
    代码如下 (参考java.awt.Container类)
    LayoutManager layoutMgr = this.layoutMgr;
    if (layoutMgr != null) {
        layoutMgr.layoutContainer(this);
    }
接口方法说明:

    //目前还没研究出其更多用处
    void addLayoutComponent(String name, Component comp);

    //目前还没研究出其更多用处   
    void removeLayoutComponent(Component comp);

   //得到此container 的理想尺寸,实现的时候常常根据该container中各个component
   //的理想尺寸和布局原则来确定
    Dimension preferredLayoutSize(Container parent);

    //得到该container的最小尺寸。
    Dimension minimumLayoutSize(Container parent);

    //container调用此方法用于布局
    void layoutContainer(Container parent);

FlowLayout 分析


预备知识(熟悉的人可以忽略这一步)
1.设定的component的大小位置
我们常常看到有很多size方法,如setBounds(),setSize(),setPreferredSize()等,真正在布局用的是
setSize()确定其大小,容器将如实按照此大小来绘制 该component.setLoaction用于确定该component
在container中的的位置,同样,容器将如实按照此位置绘制该component 
2.跨平台:由于java是垮平台语言,所以在布局的时候考虑的各个系统坐标方向可能是从左到右,也可能是
从右到左,因此,java在component中包含了getComponentOrientation()用于判断系统的方向,布局的时候,
因充分考虑到此特性

分析

在做任何布局管理器前都应确定布局原则,如FlowLayout的原则就是将component依次加入到container中
如果一行排不满,则换到下一行,可选择从左往右加,也可以选择从右往左加,还可以选择从中间开始排


[pre]//原则是将所有的component取出,并排成一行,取各个component的宽度之和(包括hgap)为container理想宽度
//取最高component的为container理想的高度
public Dimension preferredLayoutSize(Container target) {
      //获得锁
      synchronized (target.getTreeLock()) {
    Dimension dim = new Dimension(0, 0);
    //得到容器下的所有的component
    int nmembers = target.getComponentCount();
        boolean firstVisibleComponent = true;

    for (int i = 0 ; i < nmembers ; i++) {
        Component m = target.getComponent(i);
        if (m.visible) { //不可见的component将不显示
        Dimension d = m.getPreferredSize();
        dim.height = Math.max(dim.height, d.height);
                if (firstVisibleComponent) {
                    firstVisibleComponent = false;
                } else {
                    //component间应有hgap间隙
                    dim.width += hgap;
                }
                
        dim.width += d.width;
        }
    }
    Insets insets = target.getInsets();
    dim.width += insets.left + insets.right + hgap*2;
    dim.height += insets.top + insets.bottom + vgap*2;
    return dim;
      }
    }
 //container将调用此方法来布局
 //原则是总是试图将component排到一行,如果container的宽度已经不够,则另起一行,开始排
 //下一行  
   public void layoutContainer(Container target) {
      synchronized (target.getTreeLock()) {
    Insets insets = target.getInsets();
    //最大宽度
    int maxwidth = target.width - (insets.left + insets.right + hgap*2);
    int nmembers = target.getComponentCount();
    
    int x = 0, y = insets.top + vgap;
    //rowh 用于只是下一行应从哪(y坐标)开始
    //start 用于指示新的一行应该是从第几个component开始
    int rowh = 0, start = 0;

        boolean ltr = target.getComponentOrientation().isLeftToRight();

    for (int i = 0 ; i < nmembers ; i++) {
        Component m = target.getComponent(i);
        if (m.visible) {
        Dimension d = m.getPreferredSize();
        m.setSize(d.width, d.height);

        if ((x == 0) || ((x + d.width) <= maxwidth)) {
            if (x > 0) {
            x += hgap;
            }
            x += d.width;
            //确定一行的高度
            rowh = Math.max(rowh, d.height);
        } else {
            //布局该行
            //x坐标应是 insets.left + hgap 
            //y 坐标 vgap + rowh
            //从第start开始排,一直排到第i个
            moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, i, ltr);
            x = d.width;
            y += vgap + rowh;
            rowh = d.height;
            start = i;
        }
        }
    }
    //布局剩下的一行
    moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, nmembers, ltr);
      }
    }[/pre]
制作自己的布局管理器
首先,应确定自己的布局原则是什么,如下
1.将JLabel,JTextField(JTextArea,JPanel),JLabel做为一个布局单元
第一个label常用于前缀(为了方便叙说,通称为preLabel),
第二个component则作为输入内容(为了叙说方便,成为inputComponent),
第三个label作为附加说明,通常做为后缀(为了方便叙说,通成为suffixLabel。

2。容器可以设定列数,表示每行可以放多少个布局单元,每列的宽度为容器实际宽度/列数

3。对于容器中的每列, 实际是又按照preLable,inputComponent,suffixLabel分成三列
第一列的宽度为所有属于该列的布局单元中所有preLabel的最大宽度
第三列宽度同上,为有属于该列的布局单元中所有suffixLabel的最大宽度
第二列宽度为剩下的值,随着容器大小而动态改变


[pre]import java.awt.*;
import java.util.*;
import javax.swing.*;
import dl.*;

public class DialogLayout
    implements LayoutManager
{
  protected int m_divider = -1;
  protected int m_hGap = 10;
  protected int m_vGap = 5;
  //如果inputComponent为JTextField则认为该布局单元的高度为25
  public static int HEIGHT = 25;
 
  //容器平均分成多少列
  int col = 2; 

  public DialogLayout(int col)
  {
    this.col = col;
  }

  public DialogLayout()
  {
    this.col = 2;
  }

  public DialogLayout(int hGap, int vGap,int col)
  {
    m_hGap = hGap;
    m_vGap = vGap;
    this.col = col;
  }

  public void addLayoutComponent(String name, Component comp) {}

  public void removeLayoutComponent(Component comp) {}

  public Dimension preferredLayoutSize(Container parent)
  {

    int thisWidth=0;;
    int thisHeight = 0;
    Insets insets = parent.getInsets();
    Vector[] v = this.getSimpleComponents(parent,col);
    for(int i =0 ;i<col;i++)
    {
      Dimension d = this.getPreferredSize(v[i],parent);

      thisWidth = thisWidth+d.width;
      thisHeight = Math.max(thisHeight,d.height);
    }

    Vector ve = this.getComplexComponents(parent);
    int height = 0;
    for(int i= 0;i<ve.size();i++)
    {
      Component jc = (Component)ve.get(i);
      Dimension d = jc.getPreferredSize();
      height+=d.height+m_vGap;
      //height+=HEIGHTER+m_vGap;
    }
    return new Dimension(thisWidth,thisHeight+height);

  }

  public Dimension minimumLayoutSize(Container parent)
  {
    return preferredLayoutSize(parent);
  }

  public void layoutContainer(Container parent)
  {
    Insets insets = parent.getInsets();
    int startx = insets.left;
    int starty = insets.top;
    //得到实际尺寸;??
    Dimension d =parent.getSize();
    int partWidth = d.width/col;
    Vector[] v = this.getSimpleComponents(parent,col);

    Divider[] divider = new Divider[col];
    for(int i = 0;i<col;i++)
    {
      divider[i] = this.getDivider(v[i],parent);
      if(i==0)
      {
        //比较第一列的label最大值
        divider[i].left = Math.max(divider[i].left,this.getComplexDivider(parent));
      }
    }
    int cols=-1; ;

    for(int i=1,count=0;i<parent.getComponentCount();i+=3)
    {
      Component mjc = (Component)parent.getComponent(i);
      Component label = (Component)parent.getComponent(i-1);

      Component suffix = (Component)parent.getComponent(i+1);


      if(isLongTextFields(mjc))
      {
        startx = insets.left;
        //starty =starty+this.m_vGap;
        label.setBounds(startx,starty,divider[0].left,HEIGHT);

        mjc.setBounds(startx+divider[0].left+m_hGap,starty,
                      d.width-(insets.right+insets.left+divider[divider.length-1].right+divider[0].left+2*m_hGap),mjc.getPreferredSize().height);
        starty = starty + mjc.getPreferredSize().height+this.m_vGap;
        //找到一个textArea,计数器加一
        //mjc.setBounds(startx,starty,d.width,HEIGHT);
        //count++;
        cols = -1 ;

        continue;

      }
      else
      {
        //int cols = (i-1-count)/col;//得到所在列
        cols = (cols+1)%col;

        startx = partWidth*cols+insets.left;
        int w = partWidth - divider[cols].left - divider[cols].right-2*this.m_hGap;
        label.setBounds(startx,starty,divider[cols].left,HEIGHT);
        //label.setBounds(3,3,30,20);
        mjc.setBounds(startx+divider[cols].left+m_hGap,starty,w,HEIGHT);
        suffix.setBounds(startx+w+divider[cols].left+2*m_hGap,starty,divider[cols].right,HEIGHT);
        //mjc.setBounds(startx,starty,partWidth,HEIGHT);
        //starty+=HEIGHT+m_vGap;
        if(cols == divider.length-1)
        {
          starty+=HEIGHT+m_vGap;//下一行
          cols = -1;
          continue;
        }



        if(parent.getComponentCount()>(i+3))
        {
          Component mjc1 = (Component)parent.getComponent(i+3);
          if(isLongTextFields(mjc1))
          {
            starty+=HEIGHT+m_vGap;
          }
        }

      }



    }
  }

  public int getHGap()
  {
    return m_hGap;
  }

  public int getVGap()
  {
    return m_vGap;
  }






  public String toString()
  {
    return "javamonkey";
  }
  //-----------------
  protected Dimension getPreferredSize(Vector v,Container parent)
  {
    int iSize = v.size();
    //int cSize = parent.getPreferredSize();
    int lbWidth = 0;
    int sfWidth = 0;
    int mjcWidth = 0;
    int height = 0;
    Insets   insets = parent.getInsets();
    for(int i = 0;i<iSize;i++)
    {
      Component mjc = (Component)v.get(i);
      int count = this.find(parent,mjc);
      Component label = parent.getComponent(count-1);
      Component suffix = parent.getComponent(count+1);
      lbWidth = Math.max(lbWidth,label.getPreferredSize().width);
      sfWidth = Math.max(sfWidth,suffix.getPreferredSize().width);
      mjcWidth = Math.max(mjcWidth,mjc.getPreferredSize().width);
      //高度都定为label高度
      //height = height+label.getPreferredSize().height+m_vGap;
      height = height+HEIGHT+m_vGap;
    }
    int thisWidth = lbWidth+m_hGap+mjcWidth+m_hGap+sfWidth;
    int thisHeight = height;
    return new Dimension(thisWidth,thisHeight);
  }

  private Divider getDivider(Vector v,Container parent)
  {
    int iSize = v.size();
    //int cSize = parent.getPreferredSize();
    int lbWidth = 0;
    int sfWidth = 0;
    int mjcWidth = 0;

    for(int i = 0;i<iSize;i++)
    {
      Component mjc = (Component)v.get(i);
      int count = this.find(parent,mjc);
      Component label = parent.getComponent(count-1);
      Component suffix = parent.getComponent(count+1);
      lbWidth = Math.max(lbWidth,label.getPreferredSize().width);
      sfWidth = Math.max(sfWidth,suffix.getPreferredSize().width);
      mjcWidth = Math.max(mjcWidth,mjc.getPreferredSize().width);
    }
    return new Divider(lbWidth,sfWidth);
  }

  private Vector[] getSimpleComponents(Container parent,int col)
  {
    Vector v = new Vector();
    for (int k=1 ; k<parent.getComponentCount(); k+=3)
    {

      Component mjc = (Component)parent.getComponent(k);
      if(!isLongTextFields(mjc))v.add(mjc);;

    }
    Vector[] array = new Vector[col];


    for (int k=0 ; k<col; k++)
    {
      array[k] = new Vector();
    }
    for (int k=0 ; k<v.size(); k++)
    {
      int cols = k%col;

      Component mjc = (Component)v.get(k);

      array[cols].add(mjc);


    }

    return array;

  }

  private Vector getComplexComponents(Container parent)
  {
    Vector v = new Vector();
    for (int k=1 ; k<parent.getComponentCount(); k+=3)
    {

      Component mjc = (Component)parent.getComponent(k);
      if(isLongTextFields(mjc))v.add(mjc);;



    }

    return v;

  }

  private int getComplexDivider(Container parent)
  {
    Vector v = getComplexComponents(parent);
    int iSize = v.size();

    int lbWidth = 0;


    for(int i = 0;i<iSize;i++)
    {
      Component mjc = (Component)v.get(i);
      int count = this.find(parent,mjc);
      Component label = parent.getComponent(count-1);
      lbWidth = Math.max(lbWidth,label.getPreferredSize().width);

    }
    return lbWidth;

  }
  private boolean isLongTextFields(Component mjc)
  {
    if(mjc instanceof javax.swing.JTextArea) return true;
    if(mjc instanceof javax.swing.JPanel) return true;
    else
    {
      return false;
    }


  }
  private int find(Container parent,Component cp)
  {
    Component[] cps = parent.getComponents();
    for(int i=0;i<cps.length;i++)
    {
      if(cp.equals(cps[i]))return i;
    }
    return -1;
  }
}
//用于表示每个列的所有preLable,suffixLabel最大值
class Divider
{
  int left;
  int right;
  public Divider(int left,int right)
  {
    this.left = left;
    this.right =right;
  }

}[/pre]

应用布局管理器



凡是刚接触swing的,无不对布局头疼,以下是flowLayout和DialogLayout的综合使用,可以看到,只用它们俩个(有时候,还需要用BorderLayout用于宏观布局),就可以轻松做出比较美观的复杂界面

列子如下

[pre]import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2002</p>
 * <p>Company: </p>
 * @author javamonkey
 * @version 1.0
 */

public class Frame4 extends JFrame {
  private JPanel contentPane;
  

  //Construct the frame
  public Frame4() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
  //Component initialization
  private void jbInit() throws Exception  {
    //setIconImage(Toolkit.getDefaultToolkit().createImage(Frame4.class.getResource("[Your Icon]")));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(new DialogLayout());
    //第一组布局单元
    contentPane.add(new JLabel("date:"));
    contentPane.add( new JTextField());
    contentPane.add( new suffixLabel());
    //第二组布局单元
    contentPane.add( new JLabel("from:"));
    contentPane.add( new  JTextField());
    contentPane.add( new  suffixLabel());
    //第三组布局单元
    contentPane.add( new  JLabel("memo:"));
    JTextArea tx = new JTextArea();
    tx.setPreferredSize(new Dimension(0,50));
    contentPane.add(tx );
    contentPane.add( new suffixLabel());
    //第四组布局单元
    contentPane.add( new  JLabel("cash:"));
   contentPane.add(new  JTextField());
    contentPane.add( new suffixLabel("$"));


    //第五组布局单元
    JPanel pl = new JPanel();
    pl.setLayout(new FlowLayout(FlowLayout.LEFT));
    pl.setBorder(BorderFactory.createEtchedBorder());
    pl.add(new JLabel("性别:"));
    pl.add(new JRadioButton("男"));
    pl.add(new JRadioButton("女"));
    contentPane.add(new Label());
    contentPane.add(pl);
    contentPane.add(new suffixLabel());


   //


    this.setSize(new Dimension(400, 300));
    this.setTitle("Frame Title");
  }
  //Overridden so we can exit when window is closed
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
}

class suffixLabel extends JLabel
{
  public suffixLabel(String str)
  {
    super(str);
    this.setPreferredSize(new Dimension(10,0));


  }
  public suffixLabel()
  {
    super();
  }
}[/pre]

  --相关文章--
· J2EE全面介绍(二) (2007-04-13)
· 项目经验二则:读取war包中的文件及Ant使用中的OutOfMemoryError解决 (2007-04-13)
· 走向J2EE,漫长的道路 (2007-04-13)
· 步入J2EE架构和过程(2) (2007-04-13)
· 步入J2EE架构和过程(1) (2007-04-13)
· 方兴未艾的CORBA (2007-04-13)

版权所有©2005-2006 JAVA资源网 渝ICP备05007591号 虚拟主机 | 关于我们 | 联系方式 | 广告业务 | 网站地图 | 友情链接