Lightweight User Interface Toolkit (LWUIT) 为 Java ME UI 开发人员带来了许多令人印象深刻的功能。Style(风格)、Theme(主题)和 Painter 正是这样三种功能,它们可以方便开发非常吸引人且独立于设备的视觉元素。在本文中,我们将介绍如何使用它们,并探讨一些细微的问题。
我们已经使用 Sprint Wireless Toolkit 3.3.1 开发了演示应用程序。此工具包不仅提供了对 LWUIT 的良好支持,它还提供了许多非常有趣的设备仿真器,比如 HTC Touch 和 Samsung Instinct 的仿真器。如果您希望尝试使用 LWUIT,我强烈建议您在计算机上安装 Sprint WTK。
thiscomponent.getStyle().setFgColor(0xff0000);
第二种修改默认风格设置的方法是创建一种新的风格,然后将其挂接到相关的组件。Style
类拥有允许指定大多数属性的构造函数。以下代码片段设置了一个组件的新风格。
Font font = Font.createSystemFont
(Font.FACE_SYSTEM,Font.STYLE_BOLD,Font.SIZE_LARGE);
byte tr = (byte)255;
Style newstyle = new Style
(0x00ff00, 0x000000, 0xff0000, 0x4b338c, font, tr);
thiscomponent.setStyle(newstyle);
该代码设置了新的前景和背景色、文本的字体以及背景透明度。此处使用的构造函数格式如下:
Style(int fgColor, int bgColor, int fgSelectionColor,
int bgSelectionColor, Font f, byte transparency)
该构造函数还有另外一种形式,除了上述属性之外,它还允许设置图片。该构造函数不支持的属性将需要通过各自的 setter 方法来设置。
最后,通过使用 主题,还可以设置组件中所有类(比如,应用程序中的所有标签)的视觉属性,详见下文。
使用风格
现在,我们应该实现了一个简单的显示效果。接下来,我们介绍如何使用风格来指定组件的外观。我们的应用程序将提供一个组合框,如图 2 所示:
图 2. 一个简单的组合框
此处显示的该组合框的所有属性都是默认值。唯一的例外是前景选择颜色,必须更改该颜色,以提高选中项的可见性。同样,包含该组合框的窗体只修改了一个属性——它的前景色。以下代码显示了如何创建该窗体:
.
.
.
//create a form and set its title
Form f = new Form("Simple ComboBox");
//set layout manager for the form
//f.setLayout(new FlowLayout());
//set form background colour
f.getStyle().setBgColor(0xd5fff9);
.
.
.
代码的头两行是不言自明的,AWT/Swing 开发人员应该非常熟悉。第三行设置窗体的背景色属性。
该组合框也使用类似的方式来实现:
// Create a set of items
String[] items = { "Red", "Blue", "Green", "Yellow" };
//create a combobox with String[] items
ComboBox combobox = new ComboBox(items);
ComboBox
是 List
的子类,需要使用支持的数据结构。这里我们使用一个字符串数组来代表该数据结构。
准备好组合框后,我们要更改其前景选择颜色,以提高可读性。所以像对窗体所做的一样,我们写了如下一行代码:
combobox.getStyle().setFgSelectionColor(0x0000ff);
但是,当我们编译代码并运行的时候,结果非常让人吃惊——前景色保持不变!它对窗体行得通,那为什么对组合框行不通呢?为了解释这个问题,我们需要记住 LWUIT 的基本结构。像 Swing 一样,LWUIT 是围绕 MVC 概念设计的。所以呈现组件的实体和组件本身逻辑上是分离的 。同样,组合框的呈现对象需要是 Component
的子类,这表示它将拥有其自己的风格
。每个组合框创建时都有其默认的呈现器,它是 DefaultListCellRenderer
的一个实例。当绘制组合框时,使用的风格属于该呈现器,这就是在组合框的style
对象中设置前景选择颜色行不通的原因。为了使该设置生效,我们必须修改呈现器的 Style
对象:
//set foreground selection colour for
//the default combobox renderer
//this will work
DefaultListCellRenderer dlcr =
(DefaultListCellRenderer)combobox.getRenderer();
dlcr.getStyle().setFgSelectionColor(0x0000ff);
这一次,当编译该代码时,就可以正常工作了。
呈现器本身非常简单。它所要做的是就是实现接口 ListCellRenderer 中指定的方法。由于我们想要我们的组合框封装复选框,该呈现器扩展了 CheckBox
。DefaultLookAndFeel
类的 drawComboBox
方法使用该呈现器获得用于绘制组合框的组件。在这种情况下,这样获得的组件是一个复选框,如以下代码所示。
//objects of this class will be used to paint the combo boxes
class CbPainter extends CheckBox implements ListCellRenderer
{
public CbPainter()
{
super("");
}
//returns a properly initialised component
//that is ready to draw the checkbox
public Component getListCellRendererComponent
(List list,Object value,int index,boolean isSelected)
{
setText("" + value);
if (isSelected)
{
setFocus(true);
setSelected(true);
}
else
{
setFocus(false);
setSelected(false);
}
return this;
}
//returns the component required for drawing
//the focussed item
public Component getListFocusComponent(List list)
{
setText("");
setFocus(true);
setSelected(true);
return this;
}
}
组合框可以具有多种样式,而不仅仅是纯列表或复选框。他可以围绕一些其他的标准组件,或者甚至是有自己独特外观的新组件来构建。图 8 展示了一个拥有单选按钮呈现器的组合框
图 8. 具有单选按钮呈现器的组合框
要查看定义我们的演示的外观的主题,您将需要在计算机上安装 Resource Editor。启动 LWUIT 附带 或者集成到 Sprint Toolkit 中的 Resource Editor。打开 Resource Editor 后,选择 File -> Open 找到并打开资源文件。Resource Editor 将在左窗格的 Themes 下面显示 SDTheme1。单击 SDTheme1 将在右窗格中显示该主题的详细信息,如图 9 所示。
图 9. 该演示的主题
首先要注意的一点是,在顶部有一个项是以白色文字显示的。所有这样的项都是默认的。在我们的例子中,唯一特定于组件的字体设定是用于软件按钮的——左下角的 Exit 按钮。窗体标题和组合框字符串的字体没有定义。这些字体将根据默认设置呈现。
在我们较早的例子中,我们看到文本的选择颜色必须在呈现器中设置。在当前的例子中,我们知道呈现实际上是由复选框呈现器完成的。所以已经为复选框定义了背景和前景色,实际上,呈现文本的颜色和文本背景(都有接受焦点和不接受焦点两种状态)是根据这些定义。如图 10 所示。
图 10. 前景和背景颜色
在上图中,我们可以看到复选框透明度值 127 的效果(半透明)。由于该设置,下拉列表中的三个未选中的项呈中灰色。您可以更改该值,看看这些背景如何改变。顺便说以下,当您更改主题时,没必要重新构建应用程序。只需保存资源文件并单击 Run。
新主题安装好后,除了通过使用 Style
类的某个 accessor 方法手动更改的那些属性(之前 讨论过的)外,所有的可用的风格都会更新。但是,如果您想要新的主题对那些甚至手动更改的属性有效,那么使用 Style
中的某个 setter,它有两个参数,第二个是一个布尔变量。例如:
setFgColor(int fgColor, boolean override);
如果当属性被手动更改时,该布尔参数被设置为 true
,那么在新主题中指定的值也将覆盖手动设置的值。代码如下所示:
thiscomponent.getStyle().setFgColor(0xff0000, true);
Painter
Painter
界面允许组件的背景按您所想的显示。回忆一下我们关于风格的讨论,我们看到其中一个属性是 background painter(背景 painter)。在这部分,我们将看到如何使用一个简单的背景 painter。
参考我们的演示截屏,绘制文本的背景颜色无法通过风格或主题更改。当我们分析组合框(如图 11 所示)的结构以及呈现它的顺序时,原因变得很清楚。
图 11. 组合框的结构
当组合框需要重新绘制时(比如,由于它刚接受了焦点),以下事件就会按顺序进行。
- 删除旧的组合框。方法是绘制一个同样大小的填满的矩形,其透明度为 0(完全透明)。
- 然后绘制复选框选择和文本。
- 接着绘制组合框按钮。
- 最后,绘制组合框边框。
现在我们看到第一步之后,没有重新绘制组合框背景。所以这部分仍为完全透明的层,显示窗体的背景。您可以在主题中更改窗体的背景色,并且您将看到此颜色也将变为组合框的背景颜色。
如果我们现在想要组合框背景有一个不同的颜色(或者图案、图片),我们需要使用 Painter
。我们应该看到一个简单的 painter 的样子,以及如何使用它。
public class ComboBgPainter implements Painter
{
private int bgcolor;
public ComboBgPainter(int bgcolor)
{
this.bgcolor = bgcolor;
}
public void paint(Graphics g, Rectangle rect)
{
//probably redundant
//but save the current colour anyway
int color = g.getColor();
//set the given colour
g.setColor(bgcolor);
//get the position and dimension
//of rectangle to be drawn
int x = rect.getX();
int y = rect.getY();
int wd = rect.getSize().getWidth();
int ht = rect.getSize().getHeight();
//draw the filled rectangle
g.fillRect(x, y, wd, ht);
//restore colour setting
g.setColor(color);
}
}
该代码非常简单——它所做的是,使用传递给构造函数的颜色绘制一个填充的矩形。该矩形在 rect
定义和位置和方向绘制。
我们现在要做的是,将该 painter 钩挂到需要描绘其背景的组合框。我们通过在实例化两个组合框的代码后添加突出显示的行来完成。注意:将只描绘一个组合框的背景。
//create two comboboxes with these items
ComboBox combobox = new ComboBox(items);
ComboBox combobox2 = new ComboBox(items2);
//set the painter
combobox.getStyle().setBgPainter
(new ComboBgPainter(0x4b338c));
图 12 显示左侧的组合框的背景已经按预期进行了绘制。如果还希望描绘另一个组合框的背景,我们将使用同一个 painter。实际上,我们可以创建 painter 的实例,然后在所有组合框中设置同一实例。
图 12. 绘有背景的组合框
结束语
我们已经了解了如何借助 LWUIT 平台,使用 Style
、Theme
和 Painter
来创建一组有视觉吸引力的统一化组件。最近 LWUIT 已经开放了源代码。详细研究这些源代码将会是一种令人陶醉的体验,而且可以帮助您合理地利用该库并实现丰富的用户体验。