基于 Lotus Expeditor 平台构建可定制外观的自定义控件

作者:高 立娟, 软件工程师, 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/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/14751907/viewspace-617422/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值