
我們可以在組件上繪制一切來定制我們所需要的各種控制,但這篇文章的目的在于使用基本的SWT組件在一個(gè)普通的Shell中實(shí)現(xiàn)比典型SWT Shell更加美觀的效果。
(注意,僅在Windows上進(jìn)行過測試,在其它平臺上可能有所不同) 。
Shell
我們想要一個(gè)shell停留在我們的程序的上方(但不是所有程序的上方),但不獲取焦點(diǎn)、顯示在你的任務(wù)管理器或是影響用戶關(guān)注的對象。 我們也不使用"trim"來給Shell加邊框而是繪制自定義的邊框。我們所有的要求都可以通過SWT的flags參數(shù)方便的創(chuàng)建。我們可以如下創(chuàng)建Shell:
-
_shell = new Shell(Display.getDefault().getActiveShell(), SWT.NO_FOCUS | SWT.NO_TRIM);
由于我們的SWT組件在shell內(nèi)部并且我們打算對shell本身使用漸變背景,所有的組件都必須是透明的。通過在shell上設(shè)置背景色模式為SWT.INHERIT_DEFAULT來實(shí)現(xiàn)。它告訴組建繼承它們父組件的背景色。在創(chuàng)建shell之后我們簡單調(diào)用:
-
_shell.setBackgroundMode(SWT.INHERIT_DEFAULT);
那么如何在shell上得到漸變的背景色呢?默認(rèn)方式下是不支持的。你可以設(shè)置一個(gè)前景色和一個(gè)背景色但也就只能如此了。技巧是我們使用我們想要的顏色繪制一個(gè)圖像來作為shell的背景。為了在合適的時(shí)間做到這一點(diǎn),我們監(jiān)聽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();
-
}
-
}
-
});
內(nèi)容
我們的shell由3個(gè)部分組成,圖片在左上角(一個(gè)普通的CLabel ) 。 然后一個(gè)包含標(biāo)題文字的標(biāo)簽(也是CLabel ) ,最后一個(gè)標(biāo)簽顯示我們的信息(一個(gè)普通的Label) 。 我們最后使用一個(gè)Label而不是CLabel來支持比CLabel更佳的斷行和多行效果。 您當(dāng)然也可以使用幾乎任何你想要的組建。 以下是用線框分割的每個(gè)標(biāo)簽:

我們使用邊緣間隔5px的GridLayout(除頂部)除此之外沒有特別的效果創(chuàng)建,所以我就不在這里寫出代碼了(在底部供下載) 。
一些眼球效果-凋謝
在3.4的SWT中Shells支持alpha值設(shè)置,所以我們將以此來實(shí)現(xiàn)更美觀的"呈現(xiàn)"和"消失",所有我們所需要做的就是在一個(gè)線程中循環(huán)增加/減少shell的alpha通道值來實(shí)現(xiàn)shell的淡入和淡出消失。我們必須在Display線程上來做這些操作,為此提供了一個(gè)runnable讓Display對象以給定的時(shí)間間隔運(yùn)行。
在多線程的環(huán)境下記得始終檢查shell是否已經(jīng)被銷毀了。當(dāng)?shù)腼@示完成后,我們希望shell顯示一定時(shí)間然后消失掉,所以基本的流程鏈?zhǔn)?/span>:
- 創(chuàng)建shell
- 淡入shell
- 可的X秒
- 淡出shell
- 銷毀shell
所有的這些定時(shí)器或多或少就如編碼中的那樣,所以我僅提供了一個(gè)例子其余的可以參考下載中的完整代碼方面,我們需要解釋一些全局的變量。
FADE_IN_STEP
是每次迭代中alpha值的增量。
FINAL_ALPHA
是當(dāng)shell保持可見時(shí)的alpha值。一定透明度的shell將提供更佳的效果,所以默認(rèn)該值是225(255則為一個(gè)完全[不透明]的shell) 。
FADE_TIMER
是alpha變化的時(shí)間間隔。當(dāng)shell達(dá)到它的最大alpha值時(shí)調(diào)用startTimer()方法,這是一個(gè)線程,休眠若干秒,然后調(diào)用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);
-
}
堆疊的通知
最后我們要支持的,是堆疊通知。 假設(shè)我們的通知shell的整個(gè)生命周期是5秒,如果有額外的通知在第一個(gè)通知關(guān)閉之前到達(dá)呢?我們可以銷毀第一個(gè)通知,并以后者取代,但更美觀的方法是簡單地將前者升高,讓后者顯示在前者的下方。效果如下(截屏?xí)r之前的shell開始淡出,所以它們有更高的透明度) :

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