线性布局管理器,在后续swing设计中经常要用到,非常常见。
这是我根据阿发老师的讲课内容,自己学习运用的,不足之处,多多谅解。
线性布局方式,分为 水平布局 和 竖直布局
(1)、水平布局。各个子控件在水平方向上依次排列,每个控件的宽度可以单独指定, 可以使用MyXLayout
例如:
setLayout(new AfXLayout(5)); // 子控件之间的间距为5像素
add(a1, "80px"); -"80px" 固定占80像素 (不会随窗体的变化而变化)
add(a2, "0%"); -"20%" 固定占总空间的20%
add(a3, "auto"); -"auto" 采用控件的Preferred Size (根据内容的尺寸确定)
add(a4, "1w"); -"1w" 按权重分配剩余空间
权重问题;
例如,一个控件为"2w",一个控件为"3w",则它们将按2:3比例瓜分剩余的空间。
2、测试
public class Test13 extends JFrame {
//线性布局之水平布局
JPanel jp=new JPanel();//容器
JLabel j1=new ColorfulLabel3("hello",Color.GREEN);
JLabel j2=new ColorfulLabel3("hello",Color.RED);
JLabel j3=new ColorfulLabel3("hello",Color.GRAY);
JLabel j4=new ColorfulLabel3("hello",Color.BLUE);
public Test13(String title) {
super(title);
setLayout(new BorderLayout());
setSize(400, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jp.setLayout(new MyXLayoutMan(5));
add(jp,BorderLayout.CENTER);
//设置标签不透明
j1.setOpaque(true);
jp.add(j1, "80px");
j2.setOpaque(true);
jp.add(j2, "20%");
j3.setOpaque(true);
jp.add(j3, "auto");
j4.setOpaque(true);
jp.add(j4, "1w");
setVisible(true);
}
public static void main(String[] args) {
new Test13("水平布局测试");
}
}
class ColorfulLabel3 extends JLabel {
private String title;
private Color color;
public ColorfulLabel3(String title, Color color) {
super();
setText(title);
setOpaque(true);
setBackground(color);
}
@Override
public String toString() {
return "ColorfulLabel{" +
"title='" + title + '\'' +
", color=" + color +
'}';
}
}
测试结果:
2、附上阿发老师(有修改)源码内容
(1)水平布局器
public class MyXLayoutMan implements LayoutManager2
{
private List<Item> items = new ArrayList<>();
private int gap = 2;
private boolean usePerferredSize = false; // 竖立方向是否占满
public MyXLayoutMan()
{
}
public MyXLayoutMan(int gap)
{
this.gap = gap; // 控件之间的间距
}
public MyXLayoutMan(int gap, boolean usePerferredSize)
{
this.gap = gap;
this.usePerferredSize = usePerferredSize;
}
@Override
public void addLayoutComponent(String name, Component comp)
{
Item item = new Item();
item.comp = comp;
item.constraints = "auto";
items.add(item);
}
@Override
public void removeLayoutComponent(Component comp)
{
Iterator<Item> iter = items.iterator();
while(iter.hasNext())
{
Item item = iter.next();
if(item.comp == comp)
{
iter.remove();
}
}
}
@Override
public void addLayoutComponent(Component comp, Object constraints)
{
Item item = new Item();
item.comp = comp;
item.constraints = (String) constraints;
items.add(item);
}
@Override
public Dimension preferredLayoutSize(Container parent)
{
return new Dimension(30,30);
}
@Override
public Dimension minimumLayoutSize(Container parent)
{
return new Dimension(30,30);
}
@Override
public Dimension maximumLayoutSize(Container target)
{
return new Dimension(30,30);
}
@Override
public void layoutContainer(Container parent)
{
// 得到内矩形
Rectangle rect = new Rectangle(parent.getWidth(), parent.getHeight());
//Rectangle rect = parent.getBounds();
Insets insets = parent.getInsets();
rect.x += insets.left;
rect.y += insets.top;
rect.width -= (insets.left + insets.right);
rect.height -= (insets.top + insets.bottom);
// 第一轮:过滤到无效的 Item ( 有些控件是隐藏的 )
List<Item> validItems = new ArrayList<>();
for(Item it: items )
{
if(it.comp.isVisible())
validItems.add(it);
}
// 第二轮处理:百分比,像素,auto的,直接计算出结果; 权重的,在第三轮计算
int totalGapSize = gap * (validItems.size() - 1);// 间距大小
int validSize = rect.width - totalGapSize;
int totalSize = 0;
int totalWeight = 0;
for(Item it : validItems)
{
Dimension preferred = it.comp.getPreferredSize();
it.width = preferred.width;
it.height = usePerferredSize ? preferred.height : rect.height;
it.weight = 0;
// 计算宽度
String cstr = it.constraints;
if( cstr == null || cstr.length() == 0)
{
//System.out.println("(AfRowLayout) Warn: Must define constraints when added to container!");
}
else if( cstr.equals("auto"))
{
}
else if(cstr.endsWith("%")) // 按百分比
{
int num = Integer.valueOf(cstr.substring(0,cstr.length()-1));
it.width = validSize * num / 100;
}
else if(cstr.endsWith("w")) // 按权重
{
int num = Integer.valueOf(cstr.substring(0,cstr.length()-1));
it.width = 0;
it.weight = num;
}
else if(cstr.endsWith("px")) // 按权重
{
int num = Integer.valueOf(cstr.substring(0,cstr.length()-2));
it.width = num;
}
else // 按像素
{
int num = Integer.valueOf(cstr);
it.width = num;
}
totalSize += it.width;
totalWeight += it.weight;
//System.out.println("计算值:width=" + it.width + ",weight=" + it.weight);
}
// 第三轮: 剩余空间按权重分配
if( totalWeight > 0)
{
int remainSize = validSize - totalSize;
double unit = (double) remainSize / totalWeight;
for(Item it : validItems)
{
if(it.weight > 0)
{
it.width = (int)( unit * it.weight );
}
}
}
//System.out.println("总宽度: " + rect.width);
// 第四轮: 按宽度和高度布局
int x = 0;
for(Item it : validItems)
{
int y = (rect.height - it.height)/2;
if(x + it.width > rect.width)
it.width = rect.width - x;
if(it.width <= 0) break;
it.comp.setBounds(rect.x + x, rect.y + y, it.width, it.height);
//System.out.println("宽度: " + it.width);
x += it.width;
x += gap; // 间距
}
}
@Override
public float getLayoutAlignmentX(Container target)
{
return 0;
}
@Override
public float getLayoutAlignmentY(Container target)
{
return 0;
}
@Override
public void invalidateLayout(Container target)
{
}
//内部类
private static class Item
{
Component comp;
String constraints = "auto";
int width = 0;
int height = 0;
int weight = 0; // 权重
}
}
(2)垂直布局管理器
public class MyYLayoutMan implements LayoutManager2
{
private List<Item> items = new ArrayList<>();
private int gap = 2;
private boolean usePerferredSize = false; // 竖立方向是否占满
public MyYLayoutMan()
{
}
public MyYLayoutMan(int gap)
{
this.gap = gap; // 控件之间的间距
}
public MyYLayoutMan(int gap, boolean usePerferredSize)
{
this.gap = gap;
this.usePerferredSize = usePerferredSize;
}
@Override
public void addLayoutComponent(String name, Component comp)
{
Item item = new Item();
item.comp = comp;
item.constraints = "auto";
items.add(item);
}
@Override
public void removeLayoutComponent(Component comp)
{
Iterator<Item> iter = items.iterator();
while(iter.hasNext())
{
Item item = iter.next();
if(item.comp == comp)
{
iter.remove();
}
}
}
@Override
public void addLayoutComponent(Component comp, Object constraints)
{
Item item = new Item();
item.comp = comp;
item.constraints = (String) constraints;
items.add(item);
}
@Override
public Dimension preferredLayoutSize(Container parent)
{
return new Dimension(30,30);
}
@Override
public Dimension minimumLayoutSize(Container parent)
{
return new Dimension(30,30);
}
@Override
public Dimension maximumLayoutSize(Container target)
{
return new Dimension(30,30);
}
@Override
public void layoutContainer(Container parent)
{
// 得到内矩形
Rectangle rect = new Rectangle(parent.getWidth(), parent.getHeight());
//Rectangle rect = parent.getBounds();
Insets insets = parent.getInsets();
rect.x += insets.left;
rect.y += insets.top;
rect.width -= (insets.left + insets.right);
rect.height -= (insets.top + insets.bottom);
// 第一轮:过滤到无效的 Item ( 有些控件是隐藏的 )
List<Item> validItems = new ArrayList<>();
for(Item it: items )
{
if(it.comp.isVisible())
validItems.add(it);
}
// 第二轮处理:百分比,像素,auto的,直接计算出结果; 权重的,在第三轮计算
int totalGapSize = gap * (validItems.size() - 1);// 间距大小
int validSize = rect.height - totalGapSize;
int totalSize = 0;
int totalWeight = 0;
for(Item it : validItems)
{
Dimension preferred = it.comp.getPreferredSize();
it.width = usePerferredSize ? preferred.width : rect.width;
it.height = preferred.height;
it.weight = 0;
// 计算宽度
String cstr = it.constraints;
if( cstr == null || cstr.length() == 0)
{
//System.out.println("(AfColumnLayout) Warn: Must define constraints when added to container!");
}
else if( cstr.equals("auto"))
{
}
else if(cstr.endsWith("%")) // 按百分比
{
int num = Integer.valueOf(cstr.substring(0,cstr.length()-1));
it.height = validSize * num / 100;
}
else if(cstr.endsWith("w")) // 按权重
{
int num = Integer.valueOf(cstr.substring(0,cstr.length()-1));
it.height = 0;
it.weight = num;
}
else if(cstr.endsWith("px")) // 按权重
{
int num = Integer.valueOf(cstr.substring(0,cstr.length()-2));
it.height = num;
}
else // 按像素
{
int num = Integer.valueOf(cstr);
it.height = num;
}
totalSize += it.height;
totalWeight += it.weight;
//System.out.println("计算值:width=" + it.width + ",weight=" + it.weight);
}
// 第三轮: 剩余空间按权重分配
if( totalWeight > 0)
{
int remainSize = validSize - totalSize;
double unit = (double) remainSize / totalWeight;
for(Item it : validItems)
{
if(it.weight > 0)
{
it.height = (int)( unit * it.weight );
}
}
}
//System.out.println("总宽度: " + rect.width);
// 第四轮: 按宽度和高度布局
int y = 0;
for(Item it : validItems)
{
int x = 0; // 水平靠左
if(y + it.height > rect.height)
it.height = rect.height - y;
if(it.height <= 0) break;
it.comp.setBounds(rect.x + x, rect.y + y, it.width, it.height);
//System.out.println("宽度: " + it.width);
y += it.height;
y += gap; // 间距
}
}
@Override
public float getLayoutAlignmentX(Container target)
{
return 0;
}
@Override
public float getLayoutAlignmentY(Container target)
{
return 0;
}
@Override
public void invalidateLayout(Container target)
{
}
//内部类 private static class Item
{
Component comp;
String constraints = "auto";
int width = 0;
int height = 0;
int weight = 0; // 权重
}
}