• 当前位置:首页>>Linux系统教程>>Linux系统管理>>使用“惰性”评估提高 GUI 的性能
  • 使用“惰性”评估提高 GUI 的性能
  • 摘要
    缓慢的 GUI 是 Java 最大的性能问题之一。这篇 Java 技巧说明如何创建构造速度较快的 GUI,这是通过只构建必要的部件实现的。
    缓慢的图形用户界面 (GUI) 是人们对 Java 常发的牢骚。尽管构造快速的 GUI 可能既费时又费力,但如果使用我提供的这个类,您只须做少量的工作就可以加快 GUI 的速度。对于彻底的 GUI 改进而言,这只是第一步;但是,这个类是极好的一种解决方案,因为它很简单。有时这个类对性能的提高足以满足您的需要,您无须做任何额外的工作。
    方法
    这种方法很容易表述:直到必要时才构建 GUI 组件。从宏观上讲,这是所有 Java 程序的默认工作方式。毕竟,谁会在初始化时就构造程序的全部可能的框架和窗口呢?但是,我在本文提供的这个类允许您进行更精细、更惰性的构造。

    我构建的用来支持 GUI 组件惰性构造的这个实用工具类基于三点经验。第一点,大多数 GUI 面板都很简单,并且无需做任何额外的工作就可以很快完成初始化。

    将大量 GUI 组件堆积到屏幕上的面板是大多数缓慢初始化的原因。这些面板主要属于两种类型,即带选项卡的面板或滚动面板。

    第二点,通常直到要查看 GUI 组件时才需要构造它。第三点,只有在下列方法之一被调用之后 GUI 组件才是可见的:


    public void paint (Graphics)
    public void paintComponents(Graphics)
    public void paintAll (Graphics)
    public void repaint ()
    public void repaint (long)
    public void repaint (int, int, int, int)
    public void repaint (long, int, int, int, int)
    public void update (Graphics)
    创建实用工具面板类的思想是,将大多数 GUI 构建代码移出初始化块和构造函数。我们将这些代码放入一个名为 lazyConstructor() 的函数中。这个函数完成平常由 GUI 构造函数完成的大多数工作,但它本身并不是构造函数。这个实用工具面板类确保每当调用任何绘制或更新方法之前都调用一次 lazyConstructor 方法。

    在选项卡面板内使用这个面板类可以使带选项卡的面板更快地完成构造,因为最初只需构造可见的那个选项卡面板。

    代码
    该类的代码如下所示:

    import java.awt.*;

    /**
    * LazyPanel 是一个抽象基类,它提供将 Panel 对象的置入操作延迟到
    * 实际查看该面板时再进行的功能。当使用 CardLayout 和选项卡面板
    * 视图时这个类极为有用,因为它允许根据您的操作构造子视图,而不必
    * 一开始就等待全部构造完成。
    *
    * 如果子类选择覆盖下面的任一个方法,则它们必须保证被覆盖的方法
    * 首先调用父类的方法。这些方法是:
    *
    * public void paint (Graphics)
    * public void paintComponents(Graphics)
    * public void paintAll (Graphics)
    * public void repaint ()
    * public void repaint (long)
    * public void repaint (int, int, int, int)
    * public void repaint (long, int, int, int, int)
    * public void update (Graphics)
    *
    * 其中的每个方法都确保首先构造面板,然后便将调用转发给父类。
    *
    * 如果您要使用这个类,请首先创建它的一个子类,然后尽可能地
    * 将子类构造函数中的代码移到 lazyConstructor 方法中。下面是
    * 使用 LazyPanel 的一个示例:
    *
    *
    *
    * import java.awt.*;
    *
    * class BusyPanel extends LazyPanel
    * {
    * public BusyPanel (int rows, int cols)
    * {
    * this.rows = rows;
    * this.cols = cols;
    * }
    *
    * protected void lazyConstructor()
    * {
    * setLayout (new GridLayout (rows, cols));
    * for (int i = 0; i < rows * cols; ++i)
    * {
    * add (new Button (Integer.toString (i + startValue)));
    * ++startValue;
    * }
    * }

    *
    * static private int startValue = 0;
    *
    * private int rows;
    * private int cols;
    * }
    *

    * 您可以这样使用它:
    *
    * import java.awt.*;
    * import java.awt.event.*;
    *
    * class TestFrame extends Frame
    * {
    * public TestFrame ()
    * {

    * setLayout (new BorderLayout ());
    * add (nextButton, "South");
    *
    * framePanel.setLayout (layout);
    * for (int i = 0; i < 30; ++i)
    * framePanel.add (new BusyPanel (8, 8), "");
    * add (framePanel, "Center");
    *
    * nextButton.addActionListener (
    * new ActionListener()
    * {
    * public void actionPerformed (ActionEvent event)
    * {
    * layout.next (framePanel);
    * }
    * }
    * );
    *
    * setSize (400, 300);
    * }
    *
    * private CardLayout layout = new CardLayout();
    * private Button nextButton = new Button ("Next Panel");
    * private Panel framePanel = new Panel();
    *
    * static public void main (String args[])
    * {
    * (new TestFrame()).show();
    * }
    * }
    *

    * 要查看使用 LazyPanel 的优越性,请试着将 lazyConstructor() 方法中
    * 的代码移到 BusyPanel 的构造函数中,重新编译该类,然后回头再看本例。
    * 启动时的额外延迟就是 LazyPanel 类要消除的问题。
    *
    * 这种处理对 swing 同样有效。只须对 LazyPanel 稍作修改,让它
    * 扩展 JPanel(而不是 Panel)即可。
    */
    public abstract class LazyPanel extends Panel
    {
    // 我只希望调用 lazyConstructor 一次。
    private boolean lazyConstructorCalled = false;

    // Swing 的某些版本在将组件添加到它们的容器之前
    // 调用 paint() 方法。我们不希望在显示组件之前
    // 调用 lazyConstructor。
    private boolean isConstructorFinished = false;

    /**
    * 创建一个 LazyPanel。
    */
    protected LazyPanel ()
    {
    isConstructorFinished = true;
    }

    public void paint (Graphics g)
    {
    callLazyConstructor();

    super.paint (g);
    }

    public void paintAll(Graphics g)
    {
    callLazyConstructor();

    super.paintAll (g);
    }

    public void paintComponents (Graphics g)
    {
    callLazyConstructor();

    super.paintComponents (g);
    }

    public void repaint ()
    {
    callLazyConstructor();

    super.repaint();
    }

    public void repaint (long l)
    {
    callLazyConstructor();

    super.repaint (l);
    }

    public void repaint (int i1, int i2, int i3, int i4)
    {
    callLazyConstructor();

    super.repaint (i1, i2, i3, i4);
    }

    public void repaint (long l, int i1, int i2, int i3, int i4)
    {
    callLazyConstructor();

    super.repaint (l, i1, i2, i3, i4);
    }

    public void update (Graphics g)
    {
    callLazyConstructor();

    super.update (g);
    }

    /**
    * 强制调用在子类中实现的 lazyConstructor() 方法。
    * 如果多次调用某个给定对象的这个方法,则除第一次
    * 调用以外的任何其他调用不会执行任何操作。
    */
    public synchronized final void callLazyConstructor()
    {
    // 以下代码的大致思想如下所示:
    // 1) 检查该方法是否被成功调用过。
    // 如果是,只返回而不执行任何操作。
    //
    // 2) 否则 ... 调用惰性构造函数。
    // 3) 调用 validate 以使所添加的全部组件变为可见的。
    // 4) 注意我们已在运行的程序。

    if ((lazyConstructorCalled == false) && (getParent() != null))
    {
    lazyConstructor();
    lazyConstructorCalled = true;
    validate();
    }
    }

    /**
    * 任何子类都必须实现这个方法。本应该
    * 出现在子类构造函数中的大多数组件创建
    * 代码将出现在此处。请参阅上面的
    * 示例。
    */
    abstract protected void lazyConstructor ();
    }


    使用 LazyPanel
    LazyPanel 类的使用很简单,但您应该注意几点。

    别在 lazyConstructor 中发出异常
    对于面板,我们很容易编写在发生错误时发出异常的构造
  • 上一篇:Linux系统命令(文件传输)
    下一篇:在red hat linux 7.0下实现ppp server