基於 Lotus Expeditor 平臺構建可定製外觀的自定義控制元件

genusBIT發表於2009-10-26

作者:高 立娟, 軟體工程師, IBM

原文連結:http://www.ibm.com/developerworks/cn/lotus/expeditor-custom/index.html

外觀定製框架簡介

Lotus Expeditor 是 IBM 的通用託管客戶機,它允許多個應用程式同時執行在一個單一的工作臺上。為了使這些不同的應用程式具有協調一致的外觀,Lotus Expeditor 平臺提供了可定製和擴充套件的主題框架來定製應用程式的外觀。這套主題框架把對外觀的描述從程式碼中分離出來,將其放入外部 CSS 檔案和影像檔案中,開發人員通過編碼使自己的應用程式具有外觀定製能力,圖形設計人員或終端使用者就可通過直接修改相關描述檔案達到定製或個性化產品外觀的需求。主題由 theme 擴充套件點和其對應的 CSS 檔案定義。應用主題時,style. 引擎會從 registry 中讀取使用者選擇的主題,解析主題擴充套件點指定的 CSS 檔案,然後對所有向 style. service 註冊的控制元件應用主題中指定的樣式並重新繪製控制元件。接下來我們將通過一個示例程式,深入講解如何基於 Lotus Expeditor 平臺開發支援樣式和主題的自定義控制元件,並介紹如何對 SWT 標準控制元件應用樣式和主題。

平臺內支援樣式和主題的 Widget

Lotus 軟體試用下載

立即下載最新版本的 IBM Lotus 試用軟體,輕鬆體驗產品的最新特性!

Lotus Expeditor 不僅提供對標準 SWT 控制元件的定製支援,而且還內建提供了一組預設支援樣式和主題的 widget - SWidget。SWidget 具有和 SWT 標準控制元件一致的行為和介面,但具有更為豐富的定製特性。開發人員可以像使用標準 SWT 控制元件一樣在應用程式中直接使用它們,不需任何額外工作就可通過 CSS 檔案和影像檔案定製這些控制元件。表 1 列出了 Lotus Expeditor 平臺提供的預設支援樣式和主題的 widget 及它們對應的 CSS 元素。這些 widget 位於 com.ibm.rcp.swtex 外掛中,使用時需要新增對這個外掛的依賴。


表 1. 支援樣式和主題的 SWidget 及它們對應的 CSS 元素

SWidget CSS 元素名
SButton button
SMenu menu
SToolbar toolbar
SCoolbar coolbar
STabFolder tabfolder
STable table
SViewForm. viewform.
SViewStack sideshelf
SComposite composite
SSashForm. sashform.

從表 1 可以看出大多數 SWidget 對應的 CSS 元素名為它們的名稱去掉前面的 S。例如:SButton 對應的 CSS 元素名是 button。標準 SWT 控制元件對應的 CSS 元素名就是它們的名字。

接下來,我們將通過具體例項講解如何構建可定製外觀的自定義控制元件。

配置開發環境

因為 Lotus Notes V8 客戶機是構建在 Lotus Expeditor 平臺上,已經預設繼承了這種基於 CSS 的外觀定製能力,所以我們選用 Lotus Notes V8 客戶機作為我們的開發平臺。參考資料中的《擴充套件 IBM Lotus Notes V8 側欄和工具欄》介紹了配置開發環境的詳細步驟,這裡就不再贅述。

建立主題併為自定義控制元件定義樣式

建立主題需要實現主題擴充套件點 com.ibm.rcp.ui.themes。圖 1 顯示了主題擴充套件點要求的各個欄位 (id, css, label) 的值。圖 2 顯示了主題擴充套件點定義的 CSS 檔案所在的位置。清單 1 是 CSS 檔案的具體實現。如果想了解更多關於建立或定製主題方面的資訊,請參閱參考資料中的《擴充套件 IBM Lotus Notes V8 主題》。


圖 1. 主題擴充套件點及各個欄位的值(檢視大圖
圖 1. 主題擴充套件點及各個欄位的值

圖 2. 主題擴充套件點對應的 CSS 檔案
圖 2. 主題擴充套件點對應的 CSS 檔案

清單 1. CSS 檔案的具體實現

				
 countdown.css 
 1  @import url("platform.:/plugin/com.ibm.notes.branding/themes/notes.css"); 	
 2 	 	
 3  countdown { 	
 4 	 background-color: rgb(255,157,255); 
 5 	 background-image: url(images/bk.jpg); 
 6  } 	
 7 	 	
 8  digit { 	
 9 	 color:rgb(254,254,254); 
 10 	 background-color: rgb(255,157,255); 
 11 	 font-family: Century Gothic, STCaiyun, Apple Chancery; 
 12 	 font-weight: bold; 
 13 	 font-size: x-large; 
 14 } 	
 15 	
 16 .Indicator { 	
 17 	 color: rgb(254,254,254); 
 18 	 font-family: YouYuan, Apple Chancery; 
 19 	 font-weight: bold; 
 20 	 font-size: large; 
 21 } 	
 22 	
 23 .CountdownUnit { 	
 24 	 color:rgb(254,254,254); 
 25 	 font-family: Times New Roman, Apple Chancery; 
 26 	 font-weight:100; 
 27 	 font-size:xx-small; 
 28 } 	
 29 	
 30 button.Resetbutton { 	
 31 	 color: white; 
 32 	 font-family: Times New Roman, Apple Chancery; 	
 33 	 font-size:medium; 	
 34 	 font-weight: normal; 	
 35 	 border-top-width: 1; 	
 36 	 border-left-width: 1; 	
 37 	 border-bottom-width: 1; 	
 38 	 border-right-width: 1; 	
 39 	 border-radius: 5; 	
 40 	 background-color: 	
 41 		 rgb(232,198,232), 
 42 		 rgb(169,71,169), 
 43 		 rgb(198,117,198), 
 44 		 rgb(191,104,191), 
 45 		 35%, 85%, 100%; 
 46 } 

在繼續介紹之前,讓我們先預覽一下經過定製的效果。圖 3 是未經定製的倒數計時控制元件,圖 4 是應用了上面 CSS 樣式之後的倒數計時控制元件。通過對比可以看出經過定製的倒數計時控制元件要漂亮很多。


圖 3. 未經定製的倒數計時控制元件
圖 3. 未經定製的倒數計時控制元件

圖 4. 應用 CSS 樣式後的倒數計時控制元件
圖 4. 應用 CSS 樣式後的倒數計時控制元件 

對自定義控制元件進行擴充套件使其具備外觀定製能力

圖 5 顯示了倒數計時控制元件上可被定製的元素。表 2 列出了可被定製的各個元素對應的底層模型及相應的 CSS 元素。


圖 5. 倒數計時控制元件可被定製的元素
圖 5. 倒數計時控制元件可被定製的元素

表 2. 倒數計時控制元件可被定製的元素及其對應的 CSS 元素

可被定製的元素 程式模型 CSS 元素名
倒數計時控制元件 Composite countdown
倒數計時數字 Item digit
提示資訊 Label Indicator
時間單位 Label CountdownUnit
Reset 按鈕 SButton Resetbutton

倒數計時控制元件的實現位於 Countdown.java 類。它繼承自 Composite 類。為了具備外觀定製能力,控制元件需要實現 StyledWidget 介面。這個介面位於 com.ibm.rcp.swtex 外掛中。清單 2 展示了實現 StyledWidget 介面的倒數計時控制元件。


清單 2. 實現 StyledWidget 介面的自定義控制元件

				
 1 public class Countdown extends Composite implements StyledWidget {
 2                 
 3     //style. elements name
 4     public static final String DIGIT          = "digit"; //$NON-NLS-1$
 5     public static final String COUNT_DOWN        = "countdown"; //$NON-NLS-1$
 6     public static final String INDICATOR         = "Indicator"; //$NON-NLS-1$
 7     public static final String RESET_BTN         = "Resetbutton"; //$NON-NLS-1$
 8     public static final String COUNT_DOWN_UNIT = "CountdownUnit"; //$NON-NLS-1$
 9                        
 10    private CountdownSkin skin = null;
 11    。。。。。。
 12    public void setNative(boolean arg0) {
 13        //do nothing 
 14    }   
 15 
 16    public StyledElement[] getStyledElements() {
 17        String id = DefaultStyledElement.getElementIdFromWidget(this);
 18        String clazz = DefaultStyledElement.getElementClassFromWidget(this);
 19        StyledElement countdown = new DefaultStyledElement(COUNT_DOWN, null, clazz,
 20                                StyledWidget.NORMAL, id, skin, this); 
 21        StyledElement digit = new DefaultStyledElement(DIGIT, null, null, 
 22                                StyledWidget.NORMAL, id, skin, this); 
 23        return new StyledElement[] { countdown, digit }; 
 24    }
 25 
 26    ...... 
 27 } 

StyledWidget 介面定義了兩個方法:setNative 和 getStyledElements。

清單 2 的第 12-14 行是 setNative 方法的實現。這個方法設定是否對控制元件應用作業系統觀感。為了簡單起見,倒數計時控制元件不支援作業系統觀感,所以這裡不做任何操作。

第 16-24 行是 getStyledElements 方法的實現。這個方法要求返回一組 StyledElement。StyledElement 代表定製控制元件的一個 CSS 元素。Style. 引擎就是通過這個方法將樣式連結到自定義控制元件。前面提到應用主題時,style. 引擎會對所有向 style. service 註冊的控制元件應用樣式,具體實現就是通過呼叫註冊控制元件的 getStyledElements 方法獲取定製這個控制元件的所有 StyledElement, 然後從 CSS 檔案的解析結果中查詢每個 StyledElement 對應的 CSS 樣式,並把樣式資訊 ( 前景色,背景色,字型,邊框資訊等 ) 儲存到一個 map 物件中通過 StyledElement 的 setStyles 方法傳回,最後利用這些樣式資訊重新繪製控制元件。在 getStyledElements 方法裡我們返回一組 DefaultStyledElement。DefaultStyledElement 是平臺提供的對 StyledElement 的預設實現。DefaultStyledElement 有兩個建構函式,如下所示:

public DefaultStyledElement(
    String element, 
    String pseudoElement, 
    String clazz, 
    String pseudoClass, 
    String id, 
    StyledSkin skin, 
    Control control) 

public DefaultStyledElement(
    StyledElement parentElement, 
    String element, 
    String pseudoElement, 
    String clazz, 
    String pseudoClass, 
    String id, 
    StyledSkin skin, 
    Control control) 

引數:

  • element,pseudoElement:指定這個 StyledElement 在 CSS 檔案中對應的元素,偽元素的名稱。
  • clazz,pseudoClass:指定這個 StyledElement 在 CSS 檔案中對應的類,偽類的名稱。
  • id:指定這個 StyledElement 所對應的 CSS 元素的 id。
  • control: 應用樣式後 , 重新繪製 control 引數指定的控制元件。
  • Skin: StyledSkin 類的例項。

style. 引擎通過建構函式中傳入的 element,pseudoElement,clazz,pseudoClass,id 等引數將 StyledElement 與 CSS 檔案中定義的樣式進行關聯。應用樣式後,DefaultStyledElement 會將傳回的樣式資訊通過 StyledSkin 的 setStyles 方法傳給 StyledSkin, StyledSkin 負責儲存樣式資訊,然後 DefaultStyledElement 會重新繪製 control 引數指定的控制元件。

清單 2 的第 19 行指定了倒數計時控制元件對應的 CSS 元素。 DefaultStyledElement 的第一個引數 COUNT_DOWN 是值為"countdown"的常量字串,它指明這個 StyledElement 對應的 CSS 樣式是 coutdown.css 檔案中的 countdown 元素。countdown 元素定義了倒數計時控制元件的背景色和背景圖片。

第 21 行將 CSS 元素 digit 連結到倒數計時數字。digit 元素定義了倒數計時數字的前景色,背景色,字型等資訊。

我們向 DefaultStyledElement 中傳入的 skin 是 CountdownSkin 的例項。清單 3 是 CountdownSkin 的完整實現。


清單 3. CountdownSkin

				
 1   public class CountdownSkin implements StyledSkin {
 2         
 3       //style. properties for countdown 
 4       protected Color countDownBkColor; 
 5       protected Image countDownBkImg; 
 6         
 7       //style. properties for countdown digit 
 8       protected Color digitForeColor; 
 9       protected Font digitFont; 
 10     protected Color digitBkColor; 
 11        
 12     public void setStyles(StyledElement styledElement, Map styles) { 
 13         if (styles == null) { 
 14             initDefaultStyles(); 
 15         } else { 
 16             String elementName = styledElement.getElementName(); 
 17             if (elementName.equals(Countdown.COUNT_DOWN)) { 
 18                 countDownBkColor = (Color)styles.get(StyledWidget
                      .BACKGROUND_COLOR_PROPERTY);   
 19                 countDownBkImg = (Image)styles.get(StyledWidget
                      .BACKGROUND_IMAGE_PROPERTY); 
 20             } else if (elementName.equals(Countdown.DIGIT)) { 
 21                 digitForeColor = (Color)styles.get(StyledWidget.COLOR_PROPERTY); 
 22                 digitBkColor = (Color)styles.get(StyledWidget
                      .BACKGROUND_COLOR_PROPERTY); 
 23                 digitFont = ((Font)styles.get(StyledWidget.FONT_PROPERTY));
 24             } 
 25         }
 26     } 
 27        
 28     private void initDefaultStyles() { 
 29         Display defaultDisplay = Display.getDefault(); 
 30         countDownBkColor = defaultDisplay.getSystemColor(SWT
              .COLOR_WIDGET_BACKGROUND); 
 31         digitForeColor = defaultDisplay.getSystemColor(SWT
              .COLOR_INFO_FOREGROUND); 
 32         digitBkColor = defaultDisplay.getSystemColor(SWT
              .COLOR_WIDGET_BACKGROUND); 
 33    } 
 34 } 

StyledSkin 介面只定義了一個方法 setStyles(StyledElement styledElement, Map styles)。其中 styledElement 引數就是我們前面在 getStyledElements 方法裡返回的那些 StyledElement 之一。styles 引數儲存著這個 StyledElement 對應的 CSS 樣式資訊。清單 3 的第 16 行通過 styledElement 的 getElementName 方法獲得這個 StyledElement 對應的 CSS 元素名。我們還可以通過 StyledElement 的 getPseudoElementName,getClassName,getPseudoClassName,getId 等方法獲取這個 StyledElement 對應的 CSS 樣式的偽元素名,類名,偽類名,id 等資訊。第 17 行判斷當前元素是否為 countdown 元素。 如果是,第 18,19 行會從 styles 引數裡查詢 countdown 元素定義的各個屬性並將對應的值儲存下來。當傳入的元素是 digit 元素時,第 21-23 行會將 digit 元素定義的各個屬性值儲存下來。

接下來為倒數計時控制元件新增 PaintListener,以便在 paint 事件發生時利用 CountdownSkin 查詢到的樣式資訊繪製控制元件。


清單 4. 為自定義控制元件新增 PaintListener 並重新繪製控制元件

				
 1 public class Countdown extends Composite implements StyledWidget { 
 2     public Countdown(Composite parent, int style) { 
 3         super(parent, style); 
 4         setBackgroundMode(SWT.INHERIT_DEFAULT); 
 5         skin = new CountdownSkin(); 
 6         createControl(); 
 7         ...... 
 8         hookListeners(); 
 9     }   
 10        
 11    private void hookListeners() { 
 12        addPaintListener(new PaintListener() { 
 13             public void paintControl(PaintEvent event) { 
 14                  onPaint(event); 
 15             } 
 16        }); 
 17    }   
 18        
 19    private void onPaint(PaintEvent paintEvent) { 
 20        // Draw background 
 21        setBackground(skin.countDownBkColor); 
 22                
 23        // style. change or paint event. 
 24        if (skin.countDownBkImg != null) { 
 25            if (!skin.countDownBkImg.equals(bkImg)) { 
 26                // style. change 
 27                bkImg = skin.countDownBkImg; 
 28                if (bkScaledImg != null) { 
 29                    bkScaledImg.dispose(); 
 30                    bkScaledImg = null; 
 31                }                                       
 32                Rectangle imgBound = bkImg.getBounds(); 
 33                Rectangle rec = getBounds(); 
 34                ImageData imgData = bkImg.getImageData(); 
 35                Image img = bkImg; 
 36                if (rec.width != imgBound.width || rec.height != imgBound.height) { 
 37                    imgData = imgData.scaledTo(rec.width, rec.height); 
 38                    bkScaledImg = new Image(null, imgData); 
 39                    setBackgroundImage(img); 
 40                } else { 
 41                    setBackgroundImage(img); 
 42                } 
 43                                
 44            } else { 
 45                // Paint or Move 
 46                Image img = bkImg; 
 47                if (bkScaledImg != null) { 
 48                    img = bkScaledImg; 
 49                } 
 50                                
 51                Rectangle imgBound = img.getBounds(); 
 52                Rectangle rec = getBounds(); 
 53                ImageData imgData = img.getImageData(); 
 54                if ((rec.width != imgBound.width || rec.height != imgBound.height) 
                         && rec.width != 0 && rec.height != 0) { 
 55                    imgData = imgData.scaledTo(rec.width, rec.height); 
 56                    bkScaledImg = new Image(null, imgData); 
 57                    setBackgroundImage(bkScaledImg); 
 58                } else { 
 59                    setBackgroundImage(img); 
 60                } 
 61            } 
 62        } else { 
 63            if (bkScaledImg != null) { 
 64                bkScaledImg.dispose(); 
 65                bkScaledImg = null; 
 66            } 
 67            bkImg = null; 
 68            setBackgroundImage(null); 
 69         } 
 70                
 71         day.onPaint(); 
 72         hour.onPaint(); 
 73         minute.onPaint(); 
 74         second.onPaint(); 
 75    } 
 76    ...... 
 77} 

清單 4 的第 21 行根據 countdown 樣式定義的背景色繪製倒數計時控制元件的背景。第 24-69 行根據 countdown 樣式定義的背景影像繪製倒數計時控制元件的背景圖。當影像的大小與控制元件的大小不同時,會對影像進行適當的拉伸。第 71-74 呼叫倒數計時數字的 onPaint 方法更新倒數計時數字。倒數計時數字的實現位於 Digit.java 類中。在 Digit 類的 onPaint 方法裡我們可以看到如何利用 CSS 的樣式資訊繪製倒數計時數字。如清單 5 所示。


清單 5. 倒數計時數字的實現

				
 1 public class Digit extends Item { 
 2 
 3         private static final Rectangle blankRectangle = new Rectangle(0,0,0,0); 
 4 
 5         private String text; 
 6         private Composite parent = null; 
 7         private Rectangle bound = null; 
 8         private CountdownSkin skin = null; 
 9 
 10        ...... 
 11 
 12        protected void onPaint() { 
 13                if (isDisposed() || parent.isDisposed() 
 14                   || bound == null || bound.equals(blankRectangle)) { 
 15                        return; 
 16                } 
 17                
 18                GC gc = new GC(parent); 
 19                
 20                if (skin.digitBkColor != null) { 
 21                        gc.setBackground(skin.digitBkColor); 
 22                } else { 
 23                        gc.setBackground(parent.getBackground()); 
 24                } 
 25                gc.fillRectangle(bound); 
 26                
 27                if (text == null) { 
 28                        text = ""; //$NON-NLS-1$ 
 29                } 
 30                
 31                if (skin.digitForeColor != null) { 
 32                        gc.setForeground(skin.digitForeColor); 
 33                } 
 34                if (skin.digitFont != null && !skin.digitFont.isDisposed()) { 
 35                        gc.setFont(skin.digitFont); 
 36                } 
 37        
 38                Point size = gc.textExtent(text); 
 39                int x = (bound.width - size.x)/2; 
 40                if (x > 0) { 
 41                        x += bound.x; 
 42                } else { 
 43                        x = bound.x; 
 44                } 
 45                
 46                int y = (bound.height - size.y)/2;              
 47                if (y > 0) { 
 48                        y += bound.y; 
 49                } 
 50                else { 
 51                        y = bound.y;                    
 52                } 
 53                gc.drawText(text, x, y, SWT.DRAW_TRANSPARENT); 
 54                                
 55                gc.dispose(); 
 56        } 
 57} 

清單 5 的第 20-24 行根據 digit 樣式中定義的背景色繪製倒數計時數字的背景。第 32 行根據 digit 樣式定義的前景色設定倒數計時數字的顏色。第 35 行根據 digit 樣式定義的字型設定倒數計時數字的字型。第 53 行繪製倒數計時數字。

向 StyleService 註冊控制元件並對控制元件應用樣式

首先,獲取 StyleService。我們可以通過 OSGi 的 service locator 或 SWT 的 Display 獲取 StyleService。清單 6 和 7 分別展示了這兩種方法的具體實現。


清單 6. 利用 OSGi service locator 獲取 StyleService

				
ServiceTracker themeServiceTracker = new ServiceTracker(context, 
    IThemeService.class.getName(), null); 
themeServiceTracker.open();              
IThemeService themeService = (IThemeService)themeServiceTracker.getService(); 
StyleService styleService = themeService.getStyleService(); 


清單 7. 利用 SWT Display 獲取 StyleService
				
StyleService styleService = Display.getCurrent().getData(StyleService.class.getName()); 

接著,向 StyleService 註冊自定義控制元件並對控制元件應用樣式。清單 8 展示瞭如何將倒數計時控制元件註冊到 StyleService 並對其應用樣式。


清單 8. 獲取 StyleService 並將倒數計時控制元件註冊到 StyleService

				
1 public Countdown(Composite parent, int style) {
2       super(parent, style);
3       setBackgroundMode(SWT.INHERIT_DEFAULT);
4       skin = new CountdownSkin();
5       createControl();
6       StyleService styleService = (StyleService) getDisplay().getData(
7               StyleService.class.getName());
8       if (styleService != null) {
9               styleService.style(this, false, true);
10      }
11      hookListeners();
12}	

清單 8 的第 6 行通過 SWT Display 的 getData 方法獲得 StyleService, 第 9 行呼叫 StyleService 的 style. 方法對倒數計時控制元件應用樣式。

StyleService 提供了三個方法對控制元件應用樣式:

 public void style(Control control) 
 public void style(final Control control, boolean styleChildren) 
 public void style(final Control control, boolean styleChildren, boolean notify) 

control 引數指定對哪個控制元件應用樣式,styleChildren 參數列示如果控制元件是一個 composite,是否對控制元件的所有孩子應用樣式。notify 引數指明在主題發生改變時是否更新控制元件。

對 SWT 標準控制元件和具有主題感應的 SWidget 應用樣式

看到這裡,細心的讀者可能會發現我們還沒有對提示資訊,時間單位和 Reset 按鈕應用樣式。提示資訊和時間單位是用標準的 SWT Label 控制元件實現的。Lotus Expeditor 平臺已經預設地將標準 SWT 控制元件連結到 CSS 檔案中的同名樣式。所以我們只需將需要定製的控制元件註冊到 StyleService 並對控制元件應用樣式即可。清單 9 展示瞭如何對提示資訊和時間單位應用樣式。


清單 9. 將標準 SWT 控制元件註冊到 StyleService 並對其應用樣式

				
1 public Countdown(Composite parent, int style) {                         
2       。。。。。。                                               
3       StyleService styleService = (StyleService) getDisplay().getData(
4            StyleService.class.getName());
5       if (styleService != null) {                                     
6             styleService.style(indicator); 
7             styleService.style(dayslbl); 
8             styleService.style(hourslbl); 
9             styleService.style(minuteslbl); 
10           styleService.style(secondslbl);                         
11           styleService.style(this, false, true);                  
12      }                                                               
13      hookListeners();                                                
14}

清單 9 的第 6 行將提示資訊註冊到 StyleService 並對它應用樣式。第 7-10 行將時間單位註冊到 StyleService 並對它們應用樣式。

提示資訊和時間單位對應的樣式預設為主題中 label 元素定義的樣式,這與平臺中其它 Label 控制元件的樣式相同。如果想為標準 SWT 控制元件指定特定的樣式,可以通過控制元件的 setData 方法將特定的 CSS Class 或 ID 關聯到控制元件。清單 10 展示瞭如何為提示資訊指定特定的樣式。第 11 行將 coutdown.css 中的 Indicator class 繫結到提示資訊。採用同樣的方法可以為時間單位指定 CountUnit 樣式。


清單 10. 為標準的 SWT 控制元件指定特定的樣式

				
1 public class Countdown extends Composite implements StyledWidget {
2       public static final String INDICATOR = "Indicator"; //$NON-NLS-1$
3       public static final String COUNT_DOWN_UNIT = "CountdownUnit"; //$NON-NLS-1$
4       ......
5       private void createControl() {
6               ......
7 
8               indicator = new Label(root, SWT.NONE);
9               indicator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
10             indicator.setText(indicatorValue);
11             indicator.setData(StyleService.CLASS, INDICATOR);
			

對 Reset 按鈕,可以採用與提示文字相同的方式應用樣式。這裡我們用平臺內建的 SButton 控制元件構造 Reset 按鈕,看看會有什麼不同的效果。清單 11 展示瞭如何利用 SButton 構造 Reset 按鈕併為其指定特定的 CSS 元素。第 6 行利用 SButton 構造 Reset 按鈕,可以看出使用 SButton 構造一個按鈕與使用標準的 SWT Button 沒有什麼區別。第 7 行為 Reset 按鈕指定特定的樣式 Resetbutton,Resetbutton 樣式設定了漸進的背景色。為 SWidget 指定特定樣式的方法與 SWT 標準控制元件相同,都是通過 setData 方法指定樣式的 class 或 id。因為 SWidget 已經被預設註冊到 StyleService 裡了,所以這裡不需要呼叫 styleservice.style() 方法對 Reset 按鈕應用樣式。


清單 11. 利用 SButton 構造 Reset 按鈕併為其指定特定的樣式

				
1 public class Countdown extends Composite implements StyledWidget {
2       public static final String RESET_BTN = "Resetbutton"; //$NON-NLS-1$
3       ......
4       private void createControl() {
5               ...... 
6                 resetBtn = new SButton(root, SWT.NONE);
7                 resetBtn.setData(StyleService.CLASS, RESET_BTN);
8                ......
			

圖 6 是用 SWT Button 建立的 Reset 按鈕,圖 7 是用 SWidget 中的 SButton 實現的 Reset 按鈕。可以看出 SWidget 比標準的 SWT 控制元件支援更多的 CSS 屬性。


圖 6. SWT Button 建立的 Reset 按鈕
圖 6. SWT Button 建立的 Reset 按鈕

圖 7. SButton 建立的 Reset 按鈕
圖 7. SButton 建立的 Reset 按鈕 

處理不同的狀態

通過偽類 (pseduso class),可以為控制元件的不同狀態定義不同的外觀。對 SWT 標準控制元件和 SWidget,只需在 CSS 檔案中新增相應的偽類定義即可。清單 12 為 Reset 按鈕定義了 hover 和 pressed 兩個偽類。


清單 12. 處理 Reset 按鈕的不同狀態

				
	 button.Resetbutton:hover{ 
	 border-color: rgb(45,100,4); 
	 background-color: 
		 rgb(211,247,186), 
		 rgb(100,186,37), 
		 rgb(168,226,67), 
		 rgb(122,202,65), 
		 35%, 85%, 100%; 
 } 

     button.Resetbutton:pressed { 
	 border-color: rgb(45,100,4); 
	 background-color: 
		 rgb(60,129,9), 
		 rgb(60,129,9), 		
		 rgb(145,205,42), 
		 rgb(102,182,33), 		
		 rgb(91,177,30), 
		 rgb(81,170,17), 		
		 rgb(98,177,41), 
		 rgb(114,194,59), 
		 rgb(122,202,65), 
		 1%, 1%, 34%, 34%, 64%, 64%, 94%, 100%; 
 } 

圖 8 和圖 9 展示了 Reset 按鈕在這兩種狀態下與預設狀態下 ( 圖 4) 的不同。


圖 8. Mouse Hover 狀態下的 Reset 按鈕
圖 8. Mouse Hover 狀態下的 Reset 按鈕

圖 9. Mouse Pressed 狀態下的 Reset 按鈕
圖 9. Mouse Pressed 狀態下的 Reset 按鈕

對自定義控制元件,需要為偽類定義相應的 StyledElement。例如,為倒數計時控制元件新增 focus 偽類,需要在 Countdown.java 的 getStyledElements 方法中為 focus 偽類建立如下的 StyledElement:

StyledElement digitFocus = new DefaultStyledElement(COUNT_DOWN, null, null, 
    StyledWidget.FOCUS, id, skin, this)
			

並在 CountdownSkin.java 的 setStyles 方法裡儲存 focus 偽類定義的樣式資訊,然後在倒數計時控制元件獲得 focus 時利用 focus 偽類定義的樣式資訊繪製倒數計時控制元件。具體實現與 對自定義控制元件進行擴充套件使其具備外觀定製能力小節介紹的過程類似,這裡就不再詳細闡述。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14751907/viewspace-617422/,如需轉載,請註明出處,否則將追究法律責任。

相關文章