AsWing布局管理器入門
本篇介紹AsWing的布局管理器(LayoutManager),在閱讀本篇之前讀者需要對AsWing有基本認識,并且知道什么是容器,org.aswing.Container ,以下文中出現的 “容器” 都是指Container類或其子類。布局管理器是什么
和Java的Swing框架一樣,AsWing中的布局管理器用來負責容器中所有組件的尺寸與排列方式,也就是說,當開發者將組件扔到容器中后,組件在容
器中如何排列與組件顯示的尺寸都交付給該容器的布局管理器全權負責,容器本身只負責承載其內部的組件,并不對子組件的排列方式進行干預。
所以對于AsWing的使用,掌握如何使用布局是非常重要的,AsWing自帶一些常用的布局管理器,可以靈活使用,滿足大部分的排列需求,如果有特殊需求,開發者還可以擴展出新的布局方式以滿足需要。
布局管理器的運作原理
在AsWing的每一個容器組件中,都有一個LayoutManager對象,LayoutManager是一接口,所有具體的布局類都實現LayoutManager接口。
removeLayoutComponent |
這些就是LayoutManager接口的所有方法。
addLayoutComponent 和 removeLayoutComponent,用于向布局中添加組件和刪除組件,這兩個方法會在向容器中 添加/刪除 組件的時候被調用,有時addLayoutComponent 還要指定布局約束,這個約束不是所有布局都會用到,是因布局的需要而決定的,就像BorderLayout的 東南西北中,稍后會說到。
getLayoutAlignmentX 和 getLayoutAlignmentY 獲取對齊方式。
invalidateLayout 方法使布局失效,指示布局管理器放棄緩存了的信息,在下一次重繪時,重新計算布局。
layoutContainer 是布局管理器中非常重要的方法,在實現類中,在該方法中應該編寫具體的排列算法,對容器內的組件進行排列。
布局管理器所做的事情就是對容器內的組件進行排列,并且為容器計算preferredSize(組件的最佳尺寸信息),有些布局管理器也會計算
mininumSize和maxnumSize(這兩個值為組件的最小和最大尺寸,但很少用到著兩個屬性,通常最大設為一個極大值,最小設置為0,0即
可)。
組件的preferredSize、mininumSize和maxnumSize,都是給布局管理器提供參考信息的,最終容器內部組件的大小還是由布局具體實現中的算法決定,要獲得組件的實際尺寸,通過 getSize() 方法。所以在有些時候為容器內的組件設置preferredSize或許會更有用。
如何使用布局
前面說了每個容器中都有一個布局管理器,所以當我們要為一個容器指定一個布局的時候調用容器的 setLayout 方法即可,由于此項機制,我們可以在運行時動態改變容器的布局。
當需要將某個組件加入到容器中時,不是用addChild,而是要用 append 或 insert 方法,append將組件追加到容器尾部,instert將組建添加到容器的指定位置,append和insert調用后,方法內部會同時調用容器中布局對象的 addLayoutComponent方法,將組件加入到布局管理器中,這兩個方法的最后一個參數為可選參數,就是前面提到的布局約束,如果指定了該參數最終會傳遞給布局管理器的addLayoutComponent方法。如果使用addChild方法添加組件,組件會被視為普通顯示元件而得不到布局管理。
大部分布局管理器會用到容器內組件的尺寸信息,在進行排列時會作為邏輯判斷與最終設置組件的實際尺寸,這使得開發者可以給組件提供尺寸信息以達到想要的效果,一般情況下布局管理器都會優先使用組件的preferredSize,
如果有些布局明確說明以preferredSize顯示組件尺寸,那么為組件設置的preferredSize就是最終顯示出來的尺寸,當然也有可能有布
局使用絕對尺寸來顯示組件,比如EmptyLayout,要指定布局中組件的尺寸就是用
setSize。這些在不同的布局中都會有具體的情況,在使用具體的布局管理器時,需要先閱讀該布局的描述文檔,然后決定用何種方式來控制容器內組件的尺
寸。
有時候對容器內的組件尺寸信息進行了改變,卻沒有立即看到效果,那可能是由于布局管理器緩存了布局信息,這時候我們就需要使布局失效,迫使他在下一次重繪的時候重新計算排列容器內的組件。比較常用的方法是調用已發生改變的組件的revalidate方法,這樣會使調用該方法的組件與該組件外層的所有容器都標記為需要重新布局。
常用布局介紹
AsWing中自帶了很多種布局,這些布局可以滿足日常開發中的大部分需求,下面介紹幾個常用的布局方式。
-
BorderLayout
BoxLayout 只管里容器中的5個組件的排列方式,這五個組件的位置分別位于 東、南、西、北、中 方向,請看下圖:
上圖的容器中(JFrame的ContentPane)有5個按鈕(JButton)組件,分別位于 North, South, West, East 和 Center 。
要為容器指定一個BorderLayout,可以使用container.setLayout(new BorderLayout());
BorderLayout的構造函數可傳入兩個參數,即 hgap 和 vgap
組件之間的間隔為 VGap 和 HGap,VGap是縱向組件之間的間隔,HGap是橫向組件之間的間隔,可以用 setVgap 和 setHgap 來設置。位于 North 和 South 位置的組件高度為他們的 preferredHeight,而寬度就是容器的寬度,這里的 fullWidth 和 fullHeight指可用的最大寬度和高度。
位于West 和 East 位置的組件的寬度被設置為他們的 preferredWidth,高度為 fullHeigth。
Center位置即中間的那個組件的尺寸將被設為 剩余區域的大小。要在向容器中添加組件時指定組件在容器中所處的位置,就可以用 append方法中的第二個參數來制定約束。
如 :container.append(component, BorderLayout.NORTH);
這將會把component添加到容器的 North位置(北方),記住雖然我們調用的是容器的append方法,但是最終決定如何排列組件的是容器中的布局管理器,容器會調用其布局管理器的相應 方法,傳入組件和約束,布局管理器會根據約束來排列組件并且設置組件的尺寸。
-
FlowLayout
FlowLayout 是一種比較簡單的布局方式,它會將所有組件排列成一行,以組件的preferredSize顯示,一般情況下,如果一行顯示不了所有的組件,會自動換到下一行顯示。
如圖:
這是一個典型的FlowLayout布局,容器內的組件都以preferredSize顯示,由于在一行中不夠顯示所有容器,所以布局管理器將剩余的組件換到了第二行顯示。
FlowLayout的構造函數可以接受4個參數:
align, hgap, vgap, margin
align表示對齊方式,可以傳入
FlowLayout.LEFT
,FlowLayout.RIGHT
, 或FlowLayout.CENTER,
分別表示左對齊,中間對齊和右對齊。
組件之間的間隔和BorderLayout一樣,也是通過hgap和vgap定義。
margin
為一個布爾參數,指示是否將間隔作用與容器的四周,默認為true,如果設置為false的話,組件將緊貼容器的邊框。要向使用了FlowLayout的容器中添加組件,只需要簡單的調用容器的append或insert方法即可,無需指定約束,因為FlowLayout對于組件的排列是一個挨一個的,沒有特殊的約束定義。
-
BoxLayout
BoxLayout 對容器中的組件進行同一方向上的平均排列,縱向或者橫向:
BoxLayout的構造函數有兩個參數,
axis
和gap
。
axis用于指示容器中組件的排列方向,一種有2種,BoxLayout.X_AXIS 和 BoxLayout.Y_AXIS 即橫向與縱向。
gap就是制定組件之間的間隔,因為BoxLayout排列的組件不是橫向就是縱向,不會出現橫向縱向同時出現的情況,所以只要一個gap參數即可。在橫向排列的情況下,容器內組件的寬度是容器的寬度減去所有間隙的和然后平局分配得到的。組件的高度撐滿容器內的高度。
縱向排列的方式雷同,只是情況正好相反。
SoftBoxLayout
SoftBoxLayout與BoxLayout非常相似,使用上也幾乎一樣,但是,對于組件尺寸的設置有所不同。
當布局被設為橫向排列時,容器內的組件寬度會被設置成各組件的preferredWidth,高度為容器高度。
當布局被設為縱向排列時,情況正好相反,組件的寬度被設為容器寬度,高度為各組件的preferredHeight。
SoftBoxLayout的構造函數接受4個參數,axis, gap, align
前兩個參數的作用于BoxLayout構造函數的參數作用相同,排列方向和組件間隔。
第三個參數為容器內組件的對齊方式,當排列為橫向排列時,可以設為 AsWingConstants.LEFT、AsWingConstants.CENTER、AsWingConstants.RIGHT,即左、中、右。
如果排列方式為縱向排列,可以設為 AsWingConstants.TOP、AsWingConstants.CENTER、 AsWingConstants.BOTTOM,集 上、中、下。
其他布局方式
這里介紹了4種比較常用的布局方式,當然AsWing中的布局方式還不止這些,相信讀者只要掌握了這4中布局,再學習新的布局方式將不成問題。
上面的這些布局方式,都是對容器內的組件按一定規則進行排列和調整尺寸,如果要完全手動調整,進行絕對定位的話,可以使用EmptyLayout。
EmtpyLayout
是對LayoutManager接口的空實現,只是簡單的實現了接口方法,沒有具體算法,所以扔到EmptyLayout容器中的組件都可以直接
setSize,和setLocation,設置多少,運行時看到的就是多少,但是注意,由于是空實現,所以放到容器中的組件沒有默認尺寸,如果不對其進
行setSize,是看不到的。
另外還有GridLayout,對容器中的組件進行網格式的排列。CenterLayout,只管里容器中的一個組件,使其在容器中居中。FlowWrapLayout,FlowLayout的改進版,可以指定每行的最大寬度,如果大于指定寬度則開發換行。等等,讀者可以自行查看AsWing的API文檔進行查看,如果覺得沒有自己需要的,還可以自行實現LayoutManager接口,創建自己的布局方式。
綜合布局實例
下面以一個簡單的例子結束本篇教程,假設我們要實現一個類似 QQ/MSN這樣的聊天面板,那么只要用AsWing的幾種常用的布局就可以輕易實現。
先看一下最終效果:
在實現這個實例的時候,我只用了3種布局:BorderLayout、FlowLayout 和 SoftBoxLayout
下面這張圖是對整個面板的布局拆解:
呵呵,非常抱歉,本人的圖像處理能力幾乎為0…… 所以搞得比較丑。
這個面板主要非為3個部分,頂部的按鈕條,主體的文字輸入輸出區域,右側的圖片欄。 所以總的框架用BorderLayout來布局是最合適不過的了。
然后頂部(North)的按鈕排列沒有什么特殊需求,只要按順序顯示即可,所以用了FlowLayout。
主體部分(Center)用了一個AsWing的另一個容器組件,JSplitPane,該組件內僅容納2個組件,可以通過當中的一條控制線來調整內部兩個組件所占用的空間。
JSplitPane中上面部分的組件僅為一個文本框。
觀
察一下下半部分,我們需要在頂部顯示一排按鈕,中間也就是主體部分顯示一個輸入用的文本狂,下面也是用來顯示按鈕,這不又是一個BorderLayout
的用武之地么,上面的那排按鈕被放在一個FlowLayout的容器中,注意底部的發送按鈕,我們不是直接把那個按鈕放在BorderLayout的
South位置,因為如果這樣的話,按鈕的寬度將會和這個容器一樣,這樣就會顯得很長,那么我們可以在South位置再放一個容器,容器的布局使用
FlowLayout,對齊方式為右對齊,再把發送按鈕放入這個容器中,就能做到我們需要的效果啦。
最后是聊天面板的右側部分,右側可能用來顯示對話雙方的頭像或其他的一些功能面板,一般都會是一些縱向排列的組件,并且每個組件的高度可能會不同,所以我為右側面板選擇了SoftBoxLayout。
至此,一個非常簡易的聊天面板UI就完成了 :),下面是全部源代碼:
package {
import flash.display.Sprite;
import org.aswing.ASColor;
import org.aswing.AsWingConstants;
import org.aswing.AsWingManager;
import org.aswing.BorderLayout;
import org.aswing.Container;
import org.aswing.FlowLayout;
import org.aswing.JButton;
import org.aswing.JFrame;
import org.aswing.JPanel;
import org.aswing.JScrollPane;
import org.aswing.JSplitPane;
import org.aswing.JTextArea;
import org.aswing.SoftBoxLayout;
/**
* AsWing 聊天面板布局實例
*
* @author harry
*/
public class ChatPane extends Sprite {
private var frame:JFrame;
private var mainContainer:Container;
public function ChatPane() {
AsWingManager.initAsStandard(this);
frame = new JFrame(this, "AsWing Chat Pane");
mainContainer = frame.getContentPane();
mainContainer.setLayout(new BorderLayout(5));
mainContainer.append(getNorthPane(), BorderLayout.NORTH);
mainContainer.append(getCenterPane(), BorderLayout.CENTER);
mainContainer.append(getEastPane(), BorderLayout.EAST);
frame.pack();
frame.show();
}
/**
* 頂部按鈕面板
*/
protected function getNorthPane():JPanel {
var pane:JPanel = new JPanel(new FlowLayout());
for(var i:int=0; i<5; i++) {
pane.append(new JButton("Btn"+i));
}
return pane;
}
/**
* 中間文本區域
*/
protected function getCenterPane():Container {
// 文本顯示區域
var displayArea:JScrollPane = new JScrollPane(new JTextArea());
var sp:JSplitPane = new JSplitPane(AsWingConstants.VERTICAL,
false,
displayArea,
getInputArea());
return sp;
}
/**
* 文本輸入區域,包括按鈕條,輸入文本,發送按鈕
*/
protected function getInputArea():JPanel {
var inputArea:JPanel = new JPanel(new BorderLayout(0, 5));
var btnBar:JPanel = new JPanel(new FlowLayout());
for(var i:int=0; i<6; i++) btnBar.append(new JButton("B"+i));
inputArea.append(btnBar, BorderLayout.NORTH); // 將按鈕條放置在頂部。
var inputPane:JScrollPane = new JScrollPane(new JTextArea());
inputArea.append(inputPane, BorderLayout.CENTER); //輸入框放在中間
var sendButtonPane:JPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT,5,5,false));
sendButtonPane.append(new JButton("發送"));
inputArea.append(sendButtonPane, BorderLayout.SOUTH); //發送按鈕在底部
return inputArea;
}
/**
* 右側面板
*/
protected function getEastPane():JPanel {
var pane:JPanel = new JPanel(new SoftBoxLayout(SoftBoxLayout.Y_AXIS, 5));
var pic1:JPanel = new JPanel();
pic1.setOpaque(true);
pic1.setBackground(new ASColor(0xFF6600));
pic1.setPreferredHeight(100);
var pic2:JPanel = new JPanel();
pic2.setOpaque(true);
pic2.setBackground(new ASColor(0x0000FF));
pic2.setPreferredHeight(100);
pane.appendAll(pic1, pic2);
pane.setPreferredWidth(100);
return pane;
}
}
}
本篇AsWing布局入門就到這里了,如果讀者有什么疑問可以到AsWing的官方論壇進行討論 http://bbs.aswing.org 。
posted on 2008-08-11 18:38 gembin 閱讀(1032) 評論(0) 編輯 收藏 所屬分類: ActionScript3