技术开发 频道

用 IFrame 跟上潮流

  现在可以编写几行代码并改变应用程序窗口的整个外观、亲自体验 IFrame 的强大功能了。记住,IFrame 可以很简单,也可以很复杂,完全取决于您的需要。

  在这一节,我将完成几个展示开始使用 IFrame 所需要完成的基本步骤的例子。学习这些例子并在自己的计算机中运行它们,会看到仅凭阅读说明或者 API 所想像不到的效果。运行所有四个例子并分析每个例子的代码,我相信您将会理解为什么 IFrame 可以成为应用程序中一个强大的工具。

  所有例子都包含在 com.ibm.iwt.examples 包中,可以从 参考资料 中下载这个包,它们都有可以运行的 main() 方法。它们是用 JDK 1.4 编写的。

  例 1:默认 IFrame

  为了保持 IFrame “向后兼容”,我让 IFrame 的默认实现看上去与 JFrame 的完全一样,如图 5 所示:

  图 5. 默认 IFrame

  因为 IFrame 不从本机操作系统中得到其信息,所以我只能选择一种操作系统进行模拟。默认的 IFrame 实现看起来就像在 Microsoft Windows 2000 中的 JFrame 一样,我们就保持使用它了。如果在 Windows 2000 计算机中运行应用程序,那么将可以互换 JFrame 与 IFrame,不会有看得出来的差别。如果运行的不是 Windows 2000 -- 那么,第一个练习应用程序可以是模拟自己的操作系统。清单 1 显示了创建一个 IFrame 是多么容易:

  清单 1. IFrame 例 1

1 public TestApp1()
2   {
3     setTitle("Window");
4   }
5

  是的,就是这么容易(想象一下如果所有应用程序开发都这么容易,那该会怎样)。

  建议用法:在希望向后兼容 JFrame 时。

  例 2: 改变默认颜色、边框和大小

  现在看一些更有意思的代码。在这个例子中,我将标题栏框架周围的边框的背景颜色改为红色,改变窗口按钮的颜色、还改变了标题栏和窗口按钮的大小。图 6 显示了在例 2 中创建的 IFrame。

  图 6. 改变颜色、边框和大小

  仅就所说的这些改变,可以看出它们在 JFrame 中都是不可能的,但是用 IFrame 就可以很容易地实现。清单 2 显示了如何创建例 2 中使用的 IFrame:

  清单 2. IFrame 例 2

1 public TestApp2()
2   {
3     IWTUtilities.setBorderSize(new Insets(3,3,3,3));
4     setIContentPaneBorder(new LineBorder(Color.red, 3));
5     setTitleBarHeight(35);
6     setTitleBarBackground(Color.red);
7     setTitleBarButtonColors(Color.red, Color.white);
8     setTitleBarButtonSize(new Dimension(26, 26));
9     setTitle("Window");
10   }
11

  这样就行了。改变框架的外观所要做的就是这些。尽管这只是 IFrame 的一个基本的例子,只使用了六行代码,但是我们完成了一些 UI 开发人员多年来一直想要做的事情。这个基本的例子已经比当前使用的应用程序窗口中的 99% 都更先进。

  建议用法: 如果希望迅速改变框架的外观,同时又不想使它与特定于操作系统的框架有大的改变时使用。

  例 3: 利用 IWindowTitleBar 的子类

  如果希望做比颜色、大小和标题栏中的按钮这样的基本改变更多的事情,就必须继承 IWindowTitleBar 类以充分利用它提供的各种可能性。创建了子类后,就可以对标题栏做很多新的操作了,包括更高级的绘制选项以及更强大的、在标题栏中加入任何组件的能力。为什么让标题栏中的按钮和标签把自己限制住呢?加上一直想要的 JTable 吧。只要调用 IFrame 中的 setTitleBar() ,就可以创建一个应用程序开发史上非常先进的标题栏子类,并在任何 IFrame 上使用它。图 7 描绘了创建自定义窗口组件所可能产生的外观:

  图 7. 创建自定义窗口组件

  在这个例子中,通过建立 清单 2 中的框架,并用一个新的、动态的边框取代单调的、静态的红色标题栏,充分利用了所有这些新的可能性。可以从图中看到,标题已经从左边移到了中间,并使用了更有可读性的字体。我用一个在左边的“关闭”按钮取代右边三个标准按钮。最后,也许是最有创造性的,我在标题栏的右边增加了一个 JSlider,可以让这个 IFrame 的用户动态改变标题栏背景的渐变色。清单 3 中的代码片段显示了将例 2 转变为例 3 所需要的额外代码。这些对于 JFrame 来说是不可能的。

  清单 3. IFrame 例 3

1 public TestApp3()
2   {
3     IWTUtilities.setBorderSize(new Insets(3,3,3,3));
4     getIContentPane().setBorder(new LineBorder(Color.red, 3));
5     setTitleBar(new TitleBar());
6   }
7   private class TitleBar extends IWindowTitleBar implements ChangeListener
8   {
9     private Color c = new Color(0,0,0);
10     private JSlider slider;
11     public TitleBar()
12     {
13       setPreferredSize(new Dimension(0, 26));
14       removeWindowDecorations();
15       addWindowButton(IWindowButton.CLOSE, SwingConstants.LEFT);
16       setWindowButtonColors(Color.RED, Color.WHITE);
17       addTitle(getTitle(), SwingConstants.CENTER, new Font("Verdana", Font.BOLD, 14), Color.WHITE);
18       slider = new JSlider();
19       add(slider, new GroupFlowLayoutConstraints(SwingConstants.RIGHT, new Insets(3,3,3,3)));
20       slider.addChangeListener(this);
21       slider.setMaximum(255);
22       slider.setMinimum(0);
23       slider.setOpaque(false);
24     }
25     public void paintComponent(Graphics g)
26     {
27       super.paintComponent(g);
28       PaintUtilities.paintGradient(g, 0, 0, getWidth(), getHeight(), c, Color.WHITE,
29       SwingConstants.HORIZONTAL);
30     }
31     public void stateChanged(ChangeEvent e)
32     {
33       c = new Color(slider.getValue(), 0, 0);
34       repaint();
35     }
36   }
37

  分析创建这个 IFrame 的代码,可以看到它不比 清单 2 中的代码更复杂。不过,出于下面两个理由,我将所有代码移到了 IWindowTitleBar 的子类中:

  通过 重载 IWindowTitleBar 中的 paintComponent() 提供外观更精致的标题栏

  加入动态改变标题栏背景颜色的 JSlider

  因为可以在任何位置上添加任何 JComponent,所以在为标题栏创建新 widget 时可以尽情发挥想象力。对于在标题栏中创建新功能这方面来说,改变背景颜色的 JSlider 只是冰山的一角。可以开发出许多在标题栏中使用的有创造性的自定义组件。

  建议用法: 适合使用 IWindowTitleBar 的子类的情况有:

  希望在标题栏中创建更复杂的图像,而不是一种单纯的颜色

  常常会希望动态改变框架的标题栏属性,并且不希望每改变次它们时调用多个函数

  希望在标题栏中加入默认组件以外的其他组件

  例 4:结合在一起并加上透明性

  最后一个例子将其他例子结合到一起并加入了 IFrame 的最新特性——透明性。这个例子是最复杂的,并且很好地体现了 IFrame 在用最少的工作创建具有出色外观的应用程序窗口方面的强大能力。图 8 显示了具有某种透明性的复杂应用程序窗口,这种透明性使它区别其他应用程序窗口。

  图 8. 加入透明性

  首先,让我们介绍一下透明性。几年前,Microsoft Windows 应用程序开始有了标准矩形以外的框架。其中使用最多的就是 Windows Media Player,从那之后,使应用程序具有非矩形形状就成了一种趋势和很酷的事情。是的,Java 应用程序一直没有这种能力,并且在透明性方面总是差强人意,特别是当与本机绘制像素交互时。

  幸运的是,IFrame 改变了这种局面,可以开发具有透明性、甚至对于本机绘制像素透明的应用程序窗口。IFrame 中的 setTransparent() 在指定的边界内绘制指定的组件透明性。在大多数情况下,组件将是 IWindowTitleBar 或 IContentPane 的子类。应当在子类的 paintComponent() 中调用 setTransparent() ,以使它可以用它下面的正确像素重绘。

  最后提醒一下,绘制透明性速度相对来说是慢的,应当尽可能使透明区域相对较小。

  最后这个例子使用了 IFrame 的其他更高级的功能。从 清单 8 中可以看到,标题栏不再是标准的矩形标题栏了。它是自定义的形状,具有完全不同于矩形的边框。因此,在所创建的 IWindowTitleBar 子类中,必须 重载 isMouseOnBorder() 和 isInsideTitleBar() 方法,以使标题栏在绘制光标时具有正确的行为,并可以调整大小。清单 4 显示了生成例 4 中看到的应用程序窗口所需要的代码。

  清单 4. IFrame 例 4

1 public TestApp4()
2   {
3     setTitle("Window");
4     IWTUtilities.setBorderSize(new Insets(0,7,7,7));
5     IWTUtilities.setDiagonalSize(20);
6     getIContentPane().setBorder(new AppBorder());
7     getIContentPane().setBackground(new Color(255, 255, 102));
8     setTitleBar(new TitlePanel());
9   }
10   private class TitlePanel extends IWindowTitleBar
11   {
12     public TitlePanel()
13     {
14       setPreferredSize(new Dimension(800,35));
15       setFont(new Font("Verdana", Font.BOLD, 22));
16       removeWindowDecorations();
17     }
18     protected boolean isInsideTitleBar(int x, int y)
19     {
20       if (x < (int)getWidth()*.1 || x > (int)getWidth()*.9)
21         return false;
22       return true;
23     }
24     protected void isMouseOnBorder(int x, int y)
25     {
26       if (y > 10 && y > 16 && !isInsideTitleBar(x, y))
27         isMouseOnBorder = true;
28       else
29         isMouseOnBorder = false;
30     }
31     public void paintComponent(Graphics g)
32     {
33       super.paintComponent(g);
34       // ... paint code here
35       setTransparent(this, g, 0, 0, w+1, 10);
36       PaintUtilities.paintDropShadow(g, (int)(w*.1), 0, (int)(w*.8), 27);
37       Color c1 = new Color(67, 118, 135);
38       Color c2 = new Color(105, 152, 199);
39       PaintUtilities.paintGradient(g, (int)(w*.1), 0, (int)(w*.9), 14, c1, c2);
40       PaintUtilities.paintGradient(g, (int)(w*.1), 14, (int)(w*.9), 13, c2, c1);
41       Graphics2D g2 = (Graphics2D)g;
42       g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
43       g.setColor(Color.white);
44       int strW = SwingUtilities.computeStringWidth(g.getFontMetrics(), getTitle());
45       int strH = g.getFontMetrics().getMaxAscent();
46       g2.drawString(getTitle(), w/2-strW/2, h-strH/2);
47       g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
48     }
49     private void drawBorder(Graphics g, int x, int y, int w, int h)
50     {
51       g.drawLine(x, 10+y, x, h);
52       g.drawLine(x, 10+y, w-x, 10+y);
53       g.drawLine(w-x, 10+y, w-x, h);
54     }
55   }
56   private class AppBorder extends AbstractBorder
57   {
58     public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
59     {
60       // ... paint border
61     }
62   }
63

  建议用法:创建一个非百分之百矩形的框架是当前 UI 开发中的一种趋势(仅就 Windows XP 而言)。使用 IFrame 后,Java 应用程序就不会落伍了。使用透明性并 重载 IWindowTitleBar 及其所有高级函数,就可以创建具有非常精致外观的框架,可以作为整个公司应用程序的默认框架。先进的功能使 UI 开发人员可以开发出这样的框架,它可以使用户自动与某家公司关联到一起(而不只限于那种使用户自动关联到 Remond,Washington 的某家公司的框架)。

  结束语

  通过让 UI 开发人员可以完全控制他们的框架的功能 和和外观,IFrame 最终弥补了 Java 开发中的缺撼。它使 UI 开发人员可以创建只改变标题栏字体的简单 IFrame,也可以创建改变整个公司外观的复杂 IFrame。IFrame 的好处在于开发人员容易使用。它提供了开发人员改变框架所需要的所有功能,而且还非常易于扩展,使开发人员可以只改变需要改变的地方,而不会干扰其他默认行为。

  从我们完成的这些例子中可以看到,框架可能有的外观只受我们的想象力的限制。我相信在阅读过程中,您会在脑子里产生一些想法,希望读过本文后,可以用 IFrame 很快地将这些想法落实到屏幕上。

        下载IFrame源代码

        下载IFrame API文档

0
相关文章