
我們可以在組件上繪制一切來定制我們所需要的各種控制,但這篇文章的目的在于使用基本的SWT組件在一個普通的Shell中實現比典型SWT Shell更加美觀的效果。
(注意,僅在Windows上進行過測試,在其它平臺上可能有所不同) 。
Shell
我們想要一個shell停留在我們的程序的上方(但不是所有程序的上方),但不獲取焦點、顯示在你的任務管理器或是影響用戶關注的對象。 我們也不使用"trim"來給Shell加邊框而是繪制自定義的邊框。我們所有的要求都可以通過SWT的flags參數方便的創建。我們可以如下創建Shell:
-
_shell = new Shell(Display.getDefault().getActiveShell(), SWT.NO_FOCUS | SWT.NO_TRIM);
由于我們的SWT組件在shell內部并且我們打算對shell本身使用漸變背景,所有的組件都必須是透明的。通過在shell上設置背景色模式為SWT.INHERIT_DEFAULT來實現。它告訴組建繼承它們父組件的背景色。在創建shell之后我們簡單調用:
-
_shell.setBackgroundMode(SWT.INHERIT_DEFAULT);
那么如何在shell上得到漸變的背景色呢?默認方式下是不支持的。你可以設置一個前景色和一個背景色但也就只能如此了。技巧是我們使用我們想要的顏色繪制一個圖像來作為shell的背景。為了在合適的時間做到這一點,我們監聽shell上的SWT.Resize事件,代碼如下;
-
_shell.addListener(SWT.Resize, new Listener() {
-
@Override
-
public void handleEvent(Event e) {
-
try {
-
-
Rectangle rect = _shell.getClientArea();
-
-
Image newImage = new Image(Display.getDefault(), Math.max(1, rect.width), rect.height);
-
-
GC gc = new GC(newImage);
-
-
-
gc.setForeground(_bgFgGradient);
-
gc.setBackground(_bgBgGradient);
-
gc.fillGradientRectangle(rect.x, rect.y, rect.width, rect.height, true);
-
-
-
gc.setLineWidth(2);
-
gc.setForeground(_borderColor);
-
gc.drawRectangle(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2);
-
-
gc.dispose();
-
-
-
_shell.setBackgroundImage(newImage);
-
-
-
if (_oldImage != null) {
-
_oldImage.dispose();
-
}
-
_oldImage = newImage;
-
}
-
catch (Exception err) {
-
err.printStackTrace();
-
}
-
}
-
});
內容
我們的shell由3個部分組成,圖片在左上角(一個普通的CLabel ) 。 然后一個包含標題文字的標簽(也是CLabel ) ,最后一個標簽顯示我們的信息(一個普通的Label) 。 我們最后使用一個Label而不是CLabel來支持比CLabel更佳的斷行和多行效果。 您當然也可以使用幾乎任何你想要的組建。 以下是用線框分割的每個標簽:

我們使用邊緣間隔5px的GridLayout(除頂部)除此之外沒有特別的效果創建,所以我就不在這里寫出代碼了(在底部供下載) 。
一些眼球效果-凋謝
在3.4的SWT中Shells支持alpha值設置,所以我們將以此來實現更美觀的"呈現"和"消失",所有我們所需要做的就是在一個線程中循環增加/減少shell的alpha通道值來實現shell的淡入和淡出消失。我們必須在Display線程上來做這些操作,為此提供了一個runnable讓Display對象以給定的時間間隔運行。
在多線程的環境下記得始終檢查shell是否已經被銷毀了。當淡入顯示完成后,我們希望shell顯示一定時間然后消失掉,所以基本的流程鏈是:
- 創建shell
- 淡入shell
- 可的X秒
- 淡出shell
- 銷毀shell
所有的這些定時器或多或少就如編碼中的那樣,所以我僅提供了一個例子其余的可以參考下載中的完整代碼方面,我們需要解釋一些全局的變量。
FADE_IN_STEP
是每次迭代中alpha值的增量。
FINAL_ALPHA
是當shell保持可見時的alpha值。一定透明度的shell將提供更佳的效果,所以默認該值是225(255則為一個完全[不透明]的shell) 。
FADE_TIMER
是alpha變化的時間間隔。當shell達到它的最大alpha值時調用startTimer()方法,這是一個線程,休眠若干秒,然后調用fadeOut()方法。
-
private static void fadeIn(final Shell _shell) {
-
Runnable run = new Runnable() {
-
-
@Override
-
public void run() {
-
try {
-
if (_shell == null || _shell.isDisposed()) { return; }
-
-
int cur = _shell.getAlpha();
-
cur += FADE_IN_STEP;
-
-
if (cur > FINAL_ALPHA) {
-
_shell.setAlpha(FINAL_ALPHA);
-
startTimer(_shell);
-
return;
-
}
-
-
_shell.setAlpha(cur);
-
Display.getDefault().timerExec(FADE_TIMER, this);
-
}
-
catch (Exception err) {
-
err.printStackTrace();
-
}
-
}
-
-
};
-
Display.getDefault().timerExec(FADE_TIMER, run);
-
}
堆疊的通知
最后我們要支持的,是堆疊通知。 假設我們的通知shell的整個生命周期是5秒,如果有額外的通知在第一個通知關閉之前到達呢?我們可以銷毀第一個通知,并以后者取代,但更美觀的方法是簡單地將前者升高,讓后者顯示在前者的下方。效果如下(截屏時之前的shell開始淡出,所以它們有更高的透明度) :

實現這一效果是相當簡單的。 每次通知shell被打開,我們在靜態的shell數組中保留一個引用。當它淡出(并銷毀)后,從該列表中移除。因此,當一個新的shell到來后我們查看當前數組中已經存在的元素并對每一個舊的shell-heightOfNewNotificationShell
。 因此,舊的shell上移以騰出空間,但繼續如前地完成它們的淡入/淡出周期。
進一步改善
當然一切都可以做得更加美觀,也許你想要一個“ X ”關閉按鈕,或不同顏色的文字,或圓角邊框。 當前代碼中并沒有實現這些,但為你實現大多數功能避免問題。
另外請注意,我目前使用Display.getDefault().getActiveShell()
作為彈出窗口的夫shell。您可能想把它重構為一個永久性的shell以便在任何父shell被銷毀或任何彈出窗被顯示的時候都能使通知被銷毀。
代碼不是十全十美的,卻可以作為構建的基礎(如果你愿意的話) 。
下載代碼
我已創建了一個基于Eclipse項目的代碼,ImageCache / FontCache / ColorCache(它們的目的是為了緩存圖片等系統資源)。 還有一個用來存放圖片的jar。 如果你喜歡它們,可以找到更多: Gnome的顏色圖標 。
請注意您可能需要調整您的CLASSPATH設置的項目,以對應自己的SWT jar所在。
運行Tester.java然后按下按鈕啟動通知。在前一個通知消失前再次按下
。隨機圖像將顯示。
下載代碼
結論
希望這可讓您深入了解如何創建“自定義部件” (沒有多少定制繪畫)。 玩得開心!