在某些複雜的Layout情況下,果然自己製作LayoutManager是最簡單的解決方法。
承做LayoutManager或是LayoutManager2介面來作成,LayoutManager是最基本的,而LayoutManager2是它的擴張。
說到LayoutManager時,使用AWT/Swing時常常會受到它的照顧,可是意外地,卻很少人自己製作LayoutManager。
因為已經有很多現成的LayoutManager可以用了,自己再來作總是會有「自找麻煩」的感覺。但是其實製作一個
LayoutManager並沒有這麼難,試著做一次來挑戰看看吧。不僅僅是Swing,AWT也能使用,只要做一次就能夠重複利用。
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class SampleApp extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
public SampleApp(){
this.setSize(new Dimension(300,200));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new MyLayout());
actionPerformed(null);
}
public void actionPerformed(ActionEvent e){
JButton btn = new JButton("button");
btn.setFont(new Font("Serif",Font.PLAIN,18));
btn.addActionListener(this);
this.add("",btn);
}
public static void main(String[] args) {
new SampleApp().setVisible(true);
}
}
class MyLayout implements LayoutManager {
private Container container;
private ArrayList<component> components;
private int miniW = 50;
private int miniH = 20;
public MyLayout(){
components = new ArrayList<component>();
}
@Override
public void addLayoutComponent(String name, Component comp) {
components.add(comp);
if (container != null) container.doLayout();
}
@Override
public void removeLayoutComponent(Component comp) {
components.remove(comp);
if (container != null) container.doLayout();
}
@Override
public void layoutContainer(Container parent) {
container = parent;
int insetSize = 20;
int w = (parent.getWidth() - insetSize * 2) / 2;
int h = (parent.getHeight() - insetSize * 2);
int size = components.size() == 0 ? 1 : components.size();
int insetW = w / size;
int insetH = h / size;
int x = insetSize;
int y = insetSize;
for(Component c: components){
c.setBounds(new Rectangle(x,y,w,insetH));
x += insetW;
y += insetH;
}
}
@Override
public Dimension minimumLayoutSize(Container parent) {
return new Dimension(100,100);
}
@Override
public Dimension preferredLayoutSize(Container parent) {
return parent.getPreferredSize();
}
}
用MyLayout來定義上面的簡易Layout,LayoutManager的Interface定義了下面五個方法
public void addLayoutComponent(String name, Component comp)
加入Component時的處理。
public void removeLayoutComponent(Component comp)
刪除Component時的處理。
public void layoutContainer(Container parent)
再Layout處理。如果發生再Layout的要求時,會再度呼叫LayoutManager的layoutContainer。
public Dimension minimumLayoutSize(Container parent)
被Layout的Container的最小大小作為Dimension物件回傳。
public Dimension preferredLayoutSize(Container parent)
被Layout的Container的建議大小作為Dimension物件回傳。
最麻煩的地方就是layoutContainer,只要能夠處理好的話,其他就很簡單了。
LayoutManager2可以用嗎?
LayoutManager的情況下,add時只傳給String。但是想到更高級的Layout的話,add時也順便傳要做該Layout的物件,
將它作為基本來達成Layout的話會更好。想要這樣的話就得使用LayoutManager2。這是LayoutManager的方法以外,還
準備了許多其他的方法。
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class SampleApp extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
public SampleApp(){
this.setSize(new Dimension(300,200));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new MyLayout());
actionPerformed(null);
}
public void actionPerformed(ActionEvent e){
int n = new Random().nextInt(200) + 100;
JButton btn = new JButton("button [" + n + "]");
btn.setFont(new Font("Serif",Font.PLAIN,18));
btn.addActionListener(this);
this.add(btn,new Integer(n));
}
public static void main(String[] args) {
new SampleApp().setVisible(true);
}
}
class MyLayout implements LayoutManager2 {
private Container container;
private ArrayList<component> components;
private ArrayList<integer> widths;
public MyLayout(){
components = new ArrayList<component>();
widths = new ArrayList<integer>();
}
@Override
public void addLayoutComponent(String name, Component comp) {
try {
this.addLayoutComponent(
comp,new Integer(Integer.parseInt(name)));
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
@Override
public void removeLayoutComponent(Component comp) {
int n = -1;
for (int i = 0;i < components.size();i++){
if (components.get(i) == comp) n = i;
}
components.remove(comp);
widths.remove(n);
if (container != null) container.doLayout();
}
@Override
public void layoutContainer(Container parent) {
container = parent;
int insetSize = 20;
int h = (parent.getHeight() - insetSize * 2);
int size = components.size() == 0 ? 1 : components.size();
int insetH = h / size;
int x = insetSize;
int y = insetSize;
for(int i = 0;i < components.size();i++){
Component c = components.get(i);
int w = widths.get(i);
c.setBounds(new Rectangle(x,y,w,insetH));
y += insetH;
}
}
@Override
public Dimension minimumLayoutSize(Container parent) {
return new Dimension(100,100);
}
@Override
public Dimension preferredLayoutSize(Container parent) {
return parent.getPreferredSize();
}
@Override
public void addLayoutComponent(
Component comp, Object constraints) {
components.add(comp);
try {
widths.add((Integer)constraints);
} catch(ClassCastException ex){
widths.add(0);
}
if (container != null) container.doLayout();
}
@Override
public float getLayoutAlignmentX(Container target) {
return 0;
}
@Override
public float getLayoutAlignmentY(Container target) {
return 0;
}
@Override
public void invalidateLayout(Container target) {}
@Override
public Dimension maximumLayoutSize(Container target) {
return new Dimension(target.getMaximumSize());
}
}
上面的例子使用LayoutManager2,將Integer實例傳入作為寬度指定。
public void addLayoutComponent(Component comp, Object constraints)
在加入時不是傳入String而是傳入Object
public float getLayoutAlignmentX(Container target)
回傳X方向的配置值
public float getLayoutAlignmentY(Container target)
回傳Y方向的配置值
public void invalidateLayout(Container target)
使得Layout無效化
public Dimension maximumLayoutSize(Container target)
回傳Container的最大Size
參考文章:http://codezine.jp/article/detail/1626?p=4
No comments:
Post a Comment