我们都知道java的GUI界面定义是由awt类和swing类来完成的它在布局管理上面采用了容器和布局管理分离的方案也就是说容器只管将其他小件放入其中而不管这些小件是如何放置的对于布局的管理交给专门的布局管理器类(LayoutManager)来完成
其实java在GUI方面应该是并不成功的Awt类和swing类的结构非常复杂加上充斥其间的子类继承和接口实现使得要想掌握这两个类非常困难这也是很多的java程序员抱怨的事情但GUI已经成了程序发展的方向所以这里我们也得勉为其难了
现在我们来看java中布局管理器的具体实现我们前面说过java中的容器类(Container)它们只管加入小件(Meta)也就是说它只使用自己的add()方法向自己内部加入小件同时他记录这些加入其内部的小件的个数可以通过containergetComponentCount()方法类获得小件的数目通过containergetComponent(i)来获得相应小件的句柄然后LayoutManager类就可以通过这些信息来实际布局其中的小件了
java已经为我们提供了几个常用的布局管理器类例如BorderLayoutFlowLayoutGridBagLayout等等但在实际的布局上我们还是会有其他的需要我在不久前的一个问题中曾经要一个垂直的流式布局我称之为VflowLayout其实BoxLayout和GridBagLayout可以完成类似的工作但前者是swing类的成员我的客户端是一个applet不能使用而后者必须在类生成的时候指定列数而失去了灵活性所以我决定重写一个自己的布局管理器来实现经过分析所有的LayoutManager都要实现一个接口就是LayoutManager Inerface或者是他的一个子接口LayoutManager Interface后者用于复杂的布局管理例如GridCardLayoutLayoutManager有五个方法需要实现分别是
public void addLayoutComponent(String name Component comp);
public void removeLayoutComponent(Component comp);
public Dimension preferredLayoutSize(Container container);
public Dimension minimumLayoutSize(Container container);
public void layoutContainer(Container container);
第一个方法其实就是你在使用containeradd(String namecomponent comp);时调用的方法例如BorderLayout为布局管理器时但在FlowLayout中由于没有其他的附加信息所以不需要填充这个方法相应的第二个方法也就不需要填充了真正核心的方法是第三个和第五个方法前者是最终确定Container有多大的而后者就是决定Container中各个小件的实际位置的了也就是说当我们用containersetLayout(LayoutManager)后再加入小件后最后系统做的工作其实是LayoutManager layoutContainer(container);和containersetSize(LayoutManager PreferredLayoutSize(container));
下面是我的新类VflowLayout
package render_account;
import javaawt*;
import javaio*;
public class VFlowLayout implements LayoutManagerSerializable{
int hgap;
int vgap;
public VFlowLayout(){
this();
}
public VFlowLayout(int iint j){
thishgap=i;
thisvgap=j;
}
public void addLayoutComponent(String name Component comp){
}
public void removeLayoutComponent(Component comp){
}
public Dimension preferredLayoutSize(Container container){
synchronized(containergetTreeLock()){
Dimension dimension=new Dimension();
int i=containergetComponentCount();
for(int j=;j Component component = containergetComponent(j);
if(componentisVisible()){
Dimension dimension=componentgetPreferredSize();
dimensionwidth=Mathmax(dimensionwidthdimensionwidth);
if(j>)dimensionheight+=vgap;dimensionheight+=dimensionheight;
}
}
Insets insets=containergetInsets();
dimensionheight+=insetstop+insetsbottom+vgap*;
dimensionwidth+=insetsleft+insetsright+hgap*;
Dimension dimension=dimension;
return dimension;
file://return(new Dimension());
}
}
public Dimension minimumLayoutSize(Container container){
synchronized(containergetTreeLock()){
Dimension dimension=new Dimension();
int i=containergetComponentCount();
for(int j=;j Component component = containergetComponent(j);
if(componentisVisible()){
Dimension dimension=componentgetMinimumSize();
dimensionwidth=Mathmax(dimensionwidthdimensionwidth);
if(j>)
dimensionheight+=vgap;
dimensionheight+=dimensionheight;
}
}
Insets insets=containergetInsets();
dimensionheight+=insetstop+insetsbottom+vgap*;
dimensionwidth+=insetsleft+insetsright+hgap*;
Dimension dimension=dimension;
return dimension;
}
}
public void layoutContainer(Container container){
synchronized(containergetTreeLock()){
Insets insets=containergetInsets();
int vSpace=containergetSize()height(insetstop+insetsbottom+vgap*);
int componentCount=containergetComponentCount();
int left=insetsleft+hgap;
int totalHeight=;
int width=;
int componentStart=;
for(int i=;i Component component=containergetComponent(i);
if(componentisVisible()){
Dimension dimension=componentgetPreferredSize();
componentsetSize(dimensionwidthdimensionheight);
if(totalHeight== || totalHeight+dimensionheight<=vSpace){
if(totalHeight>)
totalHeight+=vgap;
totalHeight+=dimensionheight;
width=Mathmax(widthdimensionwidth);
}else{
moveComponents(containerinsetstop+vgapleftwidthcomponentStarti);
totalHeight=;
left+=hgap+width;
width=dimensionwidth;componentStart=i;
}
}
}
moveComponents(containerinsetstop+vgapleftwidthcomponentStartcomponentCount);
}
}
private void moveComponents(Container containerint topint leftint widthint componentStartint componentEnd){
synchronized(containergetTreeLock()){
for(int i=componentStart;i Component component=containergetComponent(i);
if(componentisVisible()){componentsetLocation(lefttop);top+=componentgetPreferredSize()height+vgap;
}
}
}
}
public void setHgap(int i){
thishgap=i;
}
public void setVgap(int i){
thisvgap=i;
}
public int getHgap(){
return(thishgap);
}
public int getVgap(){
return(thisvgap);
}
}
大家可以试一下