如何制作 Servlets

本节介绍JApplet,这是一个使 applet 能够使用 Swing 组件的类。 JAppletjava.applet.Applet的子类,该子类在Java Applets跟踪中进行了介绍。如果您以前从未编写过常规的 applet,我们建议您在 continue 本节之前先阅读该跟踪记录。该跟踪中提供的信息适用于 Swing 小应用程序,本节介绍了一些 exceptions。

任何包含 Swing 组件的 Servlets 都必须使用JApplet的子类来实现。这是一个使 Java 出名的 Servlets 的一个 Swing 版本-一个动画 Servlets(以其最著名的配置)显示了我们的吉祥物杜克在做手推车:

A browser with Javascript enabled is required for this page to operate properly\.  

Note:

如果看不到 Servlets 正在运行,则需要至少安装Java SE 开发套件(JDK)7版本。

您可以在TumbleItem.java中找到此 Servlets 的主要源代码。

本节讨论以下主题:

JApplet 提供的功能

因为JApplet是顶层 Swing 容器,所以每个 SwingServlets 都有一个根窗格。根窗格的存在最明显的效果是支持添加menu bar以及使用内容窗格的需要。

使用顶层容器中所述,每个顶级容器(例如JApplet)都具有一个内容窗格。内容窗格使 SwingServlets 与常规 Servlets 在以下方面有所不同:

  • 您将组件添加到 SwingServlets 的内容窗格中,而不是直接添加到 Servlets 中。 将组件添加到内容窗格向您展示方法。

  • 您在 SwingServlets 的内容窗格上而不是直接在 Servlets 上设置布局 管理 器。

  • SwingServlets 的内容窗格的默认布局 管理 器是BorderLayout。这不同于Applet的默认布局 管理 器FlowLayout

  • 您不应该将绘画代码直接放在JApplet对象中。有关如何在 Servlets 中执行自定义绘制的示例,请参见进行定制绘画

Servlets 中的线程

应该在事件调度线程上创建,查询和操作 Swing 组件,但是浏览器不会从该线程调用 applet“里程碑”方法。因此,里程碑方法initstartstopdestroy应该使用SwingUtilities方法invokeAndWait(或者,如果合适的话是invokeLater),以便在事件派发线程上执行引用 Swing 组件的代码。有关这些方法和事件分发线程的更多信息,请参见Swing 中的并发

这是init方法的示例:

public void init() {
    //Execute a job on the event-dispatching thread:
    //creating this applet's GUI.
    try {
        javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                createGUI();
            }
        });
    } catch (Exception e) {
        System.err.println("createGUI didn't successfully complete");
    }
}

private void createGUI() {
    JLabel label = new JLabel(
                       "You are successfully running a Swing applet!");
    label.setHorizontalAlignment(JLabel.CENTER);
    label.setBorder(BorderFactory.createMatteBorder(1,1,1,1,Color.black));
    getContentPane().add(label, BorderLayout.CENTER);
}

invokeLater方法不适用于此实现,因为它允许init在初始化完成之前返回,这可能导致难以调试的 applet 问题。

TumbleItem中的init方法更为复杂,如以下代码所示。与第一个示例一样,此init方法实现使用SwingUtilities.invokeAndWait在事件调度线程上执行 GUI 创建代码。此init方法设置Swing timer来触发动作事件以更新动画。此外,init使用javax.swing.SwingWorker创建一个后台任务,该后台任务加载动画图像文件,使该 applet 立即显示 GUI,而无需 await 所有资源被加载。

private void createGUI() {
    ...
    animator = new Animator();
    animator.setOpaque(true);
    animator.setBackground(Color.white);
    setContentPane(animator);
    ...
}

public void init() {
    loadAppletParameters();

    //Execute a job on the event-dispatching thread:
    //creating this applet's GUI.
    try {
        javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                createGUI();
            }
        });
    } catch (Exception e) { 
        System.err.println("createGUI didn't successfully complete");
    }

    //Set up the timer that will perform the animation.
    timer = new javax.swing.Timer(speed, this);
    timer.setInitialDelay(pause);
    timer.setCoalesce(false);
    timer.start(); //Start the animation.

    //Background task for loading images.
    SwingWorker worker = (new SwingWorker<ImageIcon[], Object>() {
            public ImageIcon[] doInBackground() {
                final ImageIcon[] innerImgs = new ImageIcon[nimgs];
            ...//Load all the images...
            return imgs;
        }
        public void done() {
            //Remove the "Loading images" label.
            animator.removeAll();
            loopslot = -1;
            try {
                imgs = get();
            } ...//Handle possible exceptions
        }

    }).execute();
}

您可以在TumbleItem.java中找到该 applet 的源代码。要查找 Servlets 所需的所有文件,请参见example index

在 SwingServlets 中使用图像

Applet类提供getImage方法,用于将图像加载到 applet 中。 getImage方法创建并返回一个Image对象,该对象代表已加载的图像。由于 Swing 组件使用Icon而不是Image来引用图片,因此 Swing 小应用程序倾向于不使用getImage。相反,SwingServlets 创建ImageIcon的实例-从图像文件加载的图标。 ImageIcon具有代码节省的好处:它可以自动处理图像跟踪。有关更多信息,请参考如何使用图标

杜克(Duke)做车轮的动画需要 17 张不同的图片。Servlets 每张图片使用一个ImageIcon并将其加载到其init方法中。由于加载图像可能需要很 Long 时间,因此将图标加载到由SwingWorker对象实现的单独线程中。这是代码:

public void init() {
    ...
    imgs = new ImageIcon[nimgs];
    (new SwingWorker<ImageIcon[], Object>() {
        public ImageIcon[] doInBackground() {
            //Images are numbered 1 to nimgs,
            //but fill array from 0 to nimgs-1.
            for (int i = 0; i < nimgs; i++) {
                imgs[i] = loadImage(i+1);
            }
            return imgs;
        }
        ...
    }).execute();

}
...
protected ImageIcon loadImage(int imageNum) {
    String path = dir + "/T" + imageNum + ".gif";
    int MAX_IMAGE_SIZE = 2400;  //Change this to the size of
                                 //your biggest image, in bytes.
    int count = 0;
    BufferedInputStream imgStream = new BufferedInputStream(
       this.getClass().getResourceAsStream(path));
    if (imgStream != null) {
        byte buf[] = new byte[MAX_IMAGE_SIZE];
        try {
            count = imgStream.read(buf);
            imgStream.close();
        } catch (java.io.IOException ioe) {
            System.err.println("Couldn't read stream from file: " + path);
            return null;
        }
        if (count <= 0) {
            System.err.println("Empty file: " + path);
            return null;
        }
        return new ImageIcon(Toolkit.getDefaultToolkit().createImage(buf));
    } else {
        System.err.println("Couldn't find file: " + path);
        return null;
    }
}

loadImage方法为指定的动画帧加载图像。它使用getResourceAsStream方法而不是通常的getResource方法来获取图像。结果代码不是很漂亮,但是getResourceAsStreamgetResource效率更高,可以将 JAR 文件中的图像加载到使用 Java Plug-in™软件执行的 applet 中。有关更多详细信息,请参见将图像加载到 Servlets

将 Servlets 嵌入 HTML 页面

您可以使用applet标签来部署一个简单的 applet。或者,您可以使用部署工具包。这是 the 脚的 DukeServlets 的代码:

<script src="https://www.java.com/js/deployJava.js" type="text/javascript">
</script><script type="text/javascript">
//<![CDATA[
    var attributes = { archive: 'https://docs.oracle.com/javase/tutorialJWS/samples/uiswing/TumbleItemProject/TumbleItem.jar',
                       codebase: 'https://docs.oracle.com/javase/tutorialJWS/samples/uiswing/TumbleItemProject',
                       code:'components.TumbleItem', width:'600', height:'95' };
    var parameters = { permissions:'sandbox', nimgs:'17', offset:'-57',
                       img: 'images/tumble', maxwidth:'120' };
    deployJava.runApplet(attributes, parameters, '1.7');
//]]>
</script><noscript>A browser with Javascript enabled is required for this page to operate properly.</noscript>

有关更多信息,请参阅Java Applets类中的部署 Servlets

JApplet API

下表列出了JApplet添加到 applet API 的有趣方法。它们使您可以访问根窗格提供的功能。您可能使用的其他方法由ComponentApplet类定义。有关常用Component方法的列表,请参见Component Methods;有关使用Applet方法的帮助,请参见Java Applets

MethodPurpose
void setContentPane(Container)

Container getContentPane()
设置或获取 Servlets 的内容窗格。内容窗格包含 Servlets 的可见 GUI 组件,并且应该是不透明的。
void setRootPane(JRootPane)
JRootPane getRootPane()
创建,设置或获取 Servlets 的根窗格。根窗格 管理Servlets 的内部,包括内容窗格,玻璃窗格等。
void setJMenuBar(JMenuBar)
JMenuBar getJMenuBar()
设置或获取 Servlets 的菜单栏,以 管理 该 Servlets 的菜单集。
void setGlassPane(Component)
Component getGlassPane()
设置或获取 Servlets 的玻璃窗格。您可以使用玻璃窗格来拦截鼠标事件。
void setLayeredPane(JLayeredPane)
JLayeredPane getLayeredPane()
设置或获取 Servlets 的分层窗格。您可以使用 Servlets 的分层窗格将组件放置在其他组件之上或之下。

Applet Example

下表显示了 SwingServlets 的示例,并在其中描述了这些示例。

ExampleWhere DescribedNotes
TumbleItemThis page动画 Servlets