在某些複雜的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