# 如何制作小程序

> 原文： [https://docs.oracle.com/javase/tutorial/uiswing/components/applet.html](https://docs.oracle.com/javase/tutorial/uiswing/components/applet.html)

本节介绍`JApplet` - 一个允许 applet 使用 Swing 组件的类。 `JApplet`是 [`java.applet.Applet`](https://docs.oracle.com/javase/8/docs/api/java/applet/Applet.html) 的子类， [Java Applets](../../deployment/applet/index.html) 跟踪。如果您之前从未编写过常规小程序，我们建议您在继续本节之前阅读该小程序。该跟踪中提供的信息适用于 Swing 小程序，本节说明了一些例外情况。

任何包含 Swing 组件的 applet 必须使用 [`JApplet`](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html) 的子类实现。这是一个帮助 Java 成名的小程序的 Swing 版本 - 一个动画小程序（以其最着名的配置）显示我们的吉祥物 Duke 做车轮：

<noscript>A browser with Javascript enabled is required for this page to operate properly.</noscript>

* * *

**Note:**  If you don't see the applet running, you need to install at least the [Java SE Development Kit (JDK) 7](http://www.oracle.com/technetwork/java/javase/downloads/index.html) release.

* * *

您可以在 [`TumbleItem.java`](../examples/components/TumbleItemProject/src/components/TumbleItem.java) 中找到此 applet 的主要源代码。

本节讨论以下主题：

*   [JApplet](#features) 提供的功能
*   [小程序中的线程](#thread)
*   [在 Swing Applet 中使用图像](#images)
*   [在 HTML 页面中嵌入 Applet](#plugin)
*   [JApplet API](#api)
*   [Applet 示例](#eg)

##  提供的功能

因为`JApplet`是顶级 Swing 容器，所以每个 Swing applet 都有一个根窗格。根窗格存在的最显着效果是支持添加[菜单栏](menu.html)以及需要使用内容窗格。

如[使用顶级容器](toplevel.html)中所述，每个顶级容器（如`JApplet`）都有一个内容窗格。内容窗格以下列方式使 Swing applet 与常规 applet 不同：

*   您将组件添加到 Swing applet 的内容窗格，而不是直接添加到 applet。 [向内容窗格添加组件](toplevel.html#contentpane)向您展示如何操作。
*   您可以在 Swing applet 的内容窗格上设置布局管理器，而不是直接在 applet 上。
*   Swing applet 的内容窗格的默认布局管理器是`BorderLayout`。这与`Applet`的默认布局管理器不同，后者是`FlowLayout`。
*   您不应将绘画代码直接放在`JApplet`对象中。有关如何在小程序中执行自定义绘制的示例，请参阅[执行自定义绘画](../painting/index.html)。

应该在事件派发线程上创建，查询和操作 Swing 组件，但是浏览器不会从该线程调用 applet“里程碑”方法。因此，里程碑方法 - `init`，`start`，`stop`和`destroy` - 应使用`SwingUtilities`方法`invokeAndWait`（或者，如果适用，`invokeLater`），以便引用的代码 Swing 组件在事件派发线程上执行。有关这些方法和事件派发线程的更多信息，请参见 Swin 中的 [Concurrency。](../concurrency/index.html)

以下是`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 计时器](../misc/timer.html)以触发更新动画的动作事件。此外，`init`使用 [`javax.swing.SwingWorker`](https://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html) 创建加载动画图像文件的后台任务，让 applet 立即显示 GUI，而无需等待加载所有资源。

```
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`](../examples/components/TumbleItemProject/src/components/TumbleItem.java) 中找到 applet 的源代码。要查找 applet 所需的所有文件，请参阅[示例索引](../examples/components/index.html#TumbleItem)。

`Applet`类提供`getImage`方法将图像加载到 applet 中。 `getImage`方法创建并返回表示加载图像的`Image`对象。因为 Swing 组件使用`Icon`而不是`Image`来引用图片，所以 Swing 小程序倾向于不使用`getImage`。相反，Swing applet 创建`ImageIcon`的实例 - 从图像文件加载的图标。 `ImageIcon`具有节省代码的优点：它可以自动处理图像跟踪。有关更多信息，请参阅[如何使用图标](../components/icon.html)。

Duke 做车轮的动画需要 17 张不同的照片。小程序每张图片使用一个`ImageIcon`并以`init`方法加载它们。由于图像可能需要很长时间才能加载，因此图标将加载到由`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`方法来获取图像。生成的代码并不漂亮，但`getResourceAsStream`比`getResource`更有效地将图像从 JAR 文件加载到使用 Java Plug-in™软件执行的 applet 中。有关详细信息，请参阅[将图像加载到 Applet](../components/icon.html#applet) 。

您可以使用`applet`标记部署一个简单的小程序。或者，您可以使用 Deployment Toolkit。以下是 cartwheeling Duke applet 的代码：

```
<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](../../deployment/applet/index.html) 课程中的[部署小程序](../../deployment/applet/deployingApplet.html)。

下表列出了`JApplet`添加到 applet API 的有趣方法。它们使您可以访问根窗格提供的功能。您可能使用的其他方法由 [`Component`](https://docs.oracle.com/javase/8/docs/api/java/awt/Component.html) 和 [`Applet`](https://docs.oracle.com/javase/8/docs/api/java/applet/Applet.html) 类定义。有关常用`Component`方法的列表，请参阅[组件方法](jcomponent.html#complookapi)，有关使用`Applet`方法的帮助，请参阅 [Java 小程序](../../deployment/applet/index.html)。

| 方法 | 目的 |
| :-- | :-- |
| [void setContentPane（Container）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html#setContentPane-java.awt.Container-)
[Container getContentPane（）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html#getContentPane--) | 设置或获取 applet 的内容窗格。内容窗格包含 applet 的可见 GUI 组件，应该是不透明的。 |
| [void setRootPane（JRootPane）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html#setRootPane-javax.swing.JRootPane-)
[JRootPane getRootPane（）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html#getRootPane--) | 创建，设置或获取 applet 的根窗格。根窗格管理 applet 的内部，包括内容窗格，玻璃窗格等。 |
| [void setJMenuBar（JMenuBar）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html#setJMenuBar-javax.swing.JMenuBar-)
[JMenuBar getJMenuBar（）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html#getJMenuBar--) | 设置或获取 applet 的菜单栏以管理 applet 的一组菜单。 |
| [void setGlassPane（Component）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html#setGlassPane-java.awt.Component-)
[Component getGlassPane（）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html#getGlassPane--) | 设置或获取 applet 的玻璃窗格。您可以使用玻璃窗格拦截鼠标事件。 |
| [void setLayeredPane（JLayeredPane）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html#setLayeredPane-javax.swing.JLayeredPane-)
[JLayeredPane getLayeredPane（）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html#getLayeredPane--) | 设置或获取 applet 的分层窗格。您可以使用 applet 的分层窗格将组件放在其他组件的顶部或后面。 |

此表显示了 Swing applet 的示例以及描述这些示例的位置。

| 例 | 在哪里描述 | 笔记 |
| :-- | :-- | :-- |
| [`TumbleItem`](../examples/components/index.html#TumbleItem) | 这一页 | 一个动画小程序 |