在《打造專業(yè)外觀-二》中,留下了3個未實現(xiàn)的功能:窗口標(biāo)題和圖標(biāo),邊緣圓角,功能按鈕。在本篇中將實現(xiàn)這些功能來完結(jié)打造專業(yè)外觀-窗口部分的講解。
一、窗口標(biāo)題。
SWT窗口Shell有public void setText(String string),public void setImage(Image image) 方法用來設(shè)置標(biāo)題和圖標(biāo)。但是現(xiàn)在窗口的樣式已經(jīng)是SWT.NO_TRIM,不再有標(biāo)題欄了,因此標(biāo)題只能自己“畫”。在paintControl方法中添加如下代碼:
else if (e.getSource() == northPanel) {
String text = getText();
if (text != null) {
gc.setForeground(titleColor);
gc.drawText(text, e.width / 2 - gc.stringExtent(text).x / 2,
e.height / 2 - gc.stringExtent(text).y / 2, true);
}
Image image = getImage();
if (text == null) {
text = "";
}
if (image != null) {
gc.drawImage(image, e.width / 2 - gc.stringExtent(text).x / 2
- image.getBounds().width - 10, e.height / 2
- image.getBounds().height / 2);
}
}
標(biāo)題文字居中顯示,圖標(biāo)居標(biāo)題文字10像素。代碼中“e.width”獲取繪圖環(huán)境上下文的長度,“gc.stringExtent(text).x”獲得標(biāo)題文字的長度,“true”表示繪制的文字不需要背景,如果是false,會看到有明顯的灰色矩形作背景。繪制圖標(biāo)不難理解。當(dāng)然通常的標(biāo)題欄是九宮格的“上部”面板,所以要為northPanel添加繪制監(jiān)聽器。northPanel.addPaintListener(this);
二、邊緣圓角
如果你不熟悉SWT的Region使用,請先研讀http://www.eclipse.org/swt/snippets/中的“create a non-rectangular shell from a transparent image”程序。
該程序通過分析Image各個像素點的alpha值,來獲取Region的填充。你可以通過本地圖片實例化一個Image對象,支持透明的圖片格式有PNG和GIF兩種,美工都會知道這一點,本程序中用到的southwest.png、southeast.png、northeast.png、northwest.png均符合,以圖片透明度來實現(xiàn)不規(guī)則窗體是常用的方法,這樣做的好處是只要更換圖片就可達(dá)到改變窗體形狀。但是有些應(yīng)用自身規(guī)定一種顏色為透明顏色,例如QQ,規(guī)定紫色為透明顏色,所以在它的實現(xiàn)中通過對圖片逐個像素點分析,發(fā)現(xiàn)RGB是紫色就認(rèn)為是透明。好,原理大致如此。下面來定義一個函數(shù)來完成次功能:
private Region getImageTransparenceRegion(Image image, int offsetX,
int offsetY) {
Region region = new Region();
final ImageData imageData = image.getImageData();
if (imageData.alphaData != null) {
Rectangle pixel = new Rectangle(0, 0, 1, 1);
for (int y = 0; y < imageData.height; y++) {
for (int x = 0; x < imageData.width; x++) {
if (imageData.getAlpha(x, y) != 255) {
pixel.x = imageData.x + x + offsetX;
pixel.y = imageData.y + y + offsetY;
region.add(pixel);
}
}
}
}
return region;
}
該方法參考了Snippet21(http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet219.java?view=co),方法返回給定圖片透明部分構(gòu)造的Region。然后在controlResized末尾添加如下代碼:
Region oldRegion = getRegion();
if (oldRegion != null && !oldRegion.isDisposed()) {
oldRegion.dispose();
}
Region newRegion = new Region();
newRegion.add(0, 0, getSize().x, getSize().y);
newRegion.subtract(getImageTransparenceRegion(northwestImage, 0, 0));
newRegion.subtract(getImageTransparenceRegion(northeastImage,
getSize().x - northeastImage.getBounds().width, 0));
newRegion.subtract(getImageTransparenceRegion(southwestImage, 0,
getSize().y - southwestImage.getBounds().y));
newRegion.subtract(getImageTransparenceRegion(southeastImage,
getSize().x - southeastImage.getBounds().width, getSize().y
- southeastImage.getBounds().height));
setRegion(newRegion);
Shell實例通過setRegion(Region region)設(shè)置區(qū)域來實現(xiàn)不規(guī)則巨型窗體,但是前提是把樣式設(shè)置成SWT.NO_TRIM。
由于窗體尺寸的變更相應(yīng)的區(qū)域也要跟著調(diào)整,所以要把邏輯寫在controlResized方法中,而且每次改變過后要釋放Region資源并重新設(shè)置新的區(qū)域。上述在初始化Region對象后,“newRegion.add(0, 0, getSize().x, getSize().y);”方法將覆蓋窗口整個區(qū)域,隨后的subtract挖掉四個角落的透明部分。
三、功能按鈕
出于時間比較緊,只添加關(guān)閉按鈕,其他按鈕如最小化、最大化原理相同。
通常按鈕有四種狀態(tài),分別是:正常態(tài)、鼠標(biāo)在上方、鼠標(biāo)按下、被禁用。這4態(tài)對應(yīng)4個圖標(biāo)。由于時間關(guān)系,只對需要注意的地方簡單介紹。具體見完整代碼。
無疑,4種狀態(tài)切換要添加鼠標(biāo)事件監(jiān)聽器。關(guān)閉按鈕通過聲明private Composite closeButton;來實現(xiàn)。具體位置本程序?qū)崿F(xiàn)是右端與northeastPanel相鄰,左邊與northPanel相鄰。在鼠標(biāo)抬起時,要檢查抬起點是否在該按鈕上,如果是才執(zhí)行關(guān)閉操作。見如下代碼
if (e.x > 0 && e.x < closeButton.getSize().x && e.y > 0
&& e.y < closeButton.getSize().y){
// 執(zhí)行關(guān)閉操作,否則鼠標(biāo)在關(guān)閉按鈕上方按下,但是不在其上松開,表明用戶放棄關(guān)閉行為。
}
重寫dispose方法如下:
@Override
public void dispose() {
try {
northwestImage.dispose();
northeastImage.dispose();
northImage.dispose();
southwestImage.dispose();
southeastImage.dispose();
southImage.dispose();
westImage.dispose();
eastImage.dispose();
closeImage.dispose();
closeOverImage.dispose();
color1.dispose();
color2.dispose();
titleColor.dispose();
} finally {
super.dispose();
}
}
首先是釋放所有SWT本地資源,然后是super.dispose();釋放窗口資源。
運行程序,界面效果如下

至此,打造專業(yè)外觀-窗口部分的講述就結(jié)束了,在這3篇幅中,主要講述了九宮格的概念,九宮格法俗話說就是“貼圖”,這個手法最常用也是最基礎(chǔ)的,你會發(fā)現(xiàn)界面美觀與否與圖片有很大關(guān)系,同時桌面編程人員需要頻繁與美工交互才能達(dá)到理想效果,如果沒有合格的美工,但憑技術(shù)很難實現(xiàn)漂亮的外觀,不過確實也存在只用多邊形與曲線繪制組件的高手,swing的L&F就是這么實現(xiàn)的,但是貼圖的好處是只要圖片替換,外觀也跟著替換,不用更改代碼。
本程序只作為您設(shè)計的參考,欠缺還很多,并且沒有對代碼的健壯性、異常情況過多考慮,由于swt資源必須手工釋放,如dispose方法中那樣,其實那是最基本的,在實際環(huán)境下這么做還很有限,而且nullPoint異常也沒有過多考慮。這都需要你自己去實現(xiàn)。
最終的完整程序這里下載