这些Java教程是针对JDK 8编写的。本页中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请参阅Java语言更改,了解Java SE 9及后续版本中更新的语言特性的概述。
请参阅JDK发行说明,了解所有JDK版本的新功能、增强功能以及已删除或弃用选项的信息。
本节介绍了 JApplet —— 一个使applet能够使用Swing组件的类。 JApplet 是 java.applet.Applet 的子类,该类在 Java Applets 部分有详细介绍。如果您以前从未编写过普通的applet,请在阅读本节之前阅读该部分。该部分提供的信息适用于Swing applet,但也有一些例外情况,本节会进行解释。
包含Swing组件的任何applet必须使用 JApplet 的子类来实现。下面是一个Swing版本的帮助Java走红的applet之一 —— 一个动画applet,最著名的配置是显示我们的吉祥物Duke做空翻:
您可以在 TumbleItem.java 中找到该applet的主要源代码。
本节讨论以下主题:
由于JApplet是一个顶级的Swing容器,每个Swing applet都有一个根窗格。根窗格的最明显的特点是支持添加一个 菜单栏,以及使用内容窗格的需求。
如在使用顶层容器中所描述的,每个顶层容器,如JApplet,都有一个单独的内容窗格。内容窗格使得Swing applet与普通applet有以下不同之处:
BorderLayout。这与Applet的默认布局管理器FlowLayout不同。JApplet对象中放置绘图代码。请参见执行自定义绘图中有关如何在applet中执行自定义绘图的示例。Swing组件应该在事件调度线程上创建、查询和操作,但浏览器不会从该线程调用applet的“里程碑”方法。因此,里程碑方法init、start、stop和destroy应该使用SwingUtilities的invokeAndWait方法(或者如果适用的话,invokeLater),以便引用Swing组件的代码在事件调度线程上执行。有关这些方法和事件调度线程的更多信息,请参见Swing中的并发。
下面是一个init方法的示例:
public void init() {
//在事件调度线程上执行一个任务:
//创建这个applet的GUI。
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI没有成功完成");
}
}
private void createGUI() {
JLabel label = new JLabel(
"您正在成功运行一个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定时器来触发更新动画的动作事件。此外,init使用javax.swing.SwingWorker创建一个后台任务,用于加载动画图像文件,让applet立即呈现GUI,而不需要等待所有资源加载完成。
private void createGUI() {
...
animator = new Animator();
animator.setOpaque(true);
animator.setBackground(Color.white);
setContentPane(animator);
...
}
public void init() {
loadAppletParameters();
//在事件调度线程上执行一个任务:创建此小程序的GUI。
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI没有成功完成");
}
//设置执行动画的计时器。
timer = new javax.swing.Timer(speed, this);
timer.setInitialDelay(pause);
timer.setCoalesce(false);
timer.start(); //启动动画。
//用于加载图像的后台任务。
SwingWorker worker = (new SwingWorker<ImageIcon[], Object>() {
public ImageIcon[] doInBackground() {
final ImageIcon[] innerImgs = new ImageIcon[nimgs];
...//加载所有图像...
return imgs;
}
public void done() {
//移除“正在加载图像”的标签。
animator.removeAll();
loopslot = -1;
try {
imgs = get();
} ...//处理可能的异常
}
}).execute();
}
你可以在TumbleItem.java中找到小程序的源代码。要找到小程序所需的所有文件,请参阅示例索引。
Applet类提供了getImage方法来加载图像到小程序中。 getImage方法创建并返回表示加载的图像的Image对象。因为Swing组件使用Icon而不是Image来引用图片,所以Swing小程序往往不使用getImage。相反,Swing小程序创建ImageIcon的实例 - 从图像文件加载的图标。 ImageIcon自动处理图像跟踪,这是它的一个节省代码的好处。请参阅如何使用图标以获取更多信息。
杜克做手脚的动画需要17张不同的图片。小程序使用每张图片一个ImageIcon,并在其init方法中加载它们。由于图像可能需要很长时间来加载,这些图标是在由SwingWorker对象实现的单独线程中加载的。以下是代码:
public void init() {
...
imgs = new ImageIcon[nimgs];
(new SwingWorker<ImageIcon[], Object>() {
public ImageIcon[] doInBackground() {
//从1到nimgs编号的图像,
//但将数组从0到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; //将此值更改为最大图像的大小(以字节为单位)。
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("无法从文件读取流:" + path);
return null;
}
if (count <= 0) {
System.err.println("空文件:" + path);
return null;
}
return new ImageIcon(Toolkit.getDefaultToolkit().createImage(buf));
} else {
System.err.println("找不到文件:" + path);
return null;
}
}
loadImage 方法加载指定动画帧的图像。它使用 getResourceAsStream 方法而不是通常的 getResource 方法来获取图像。由于使用 Java Plug-in™ 软件在 JAR 文件中加载图像的 applet 中,getResourceAsStream 方法比 getResource 方法更高效。有关详细信息,请参阅 将图像加载到 Applet 中。
您可以使用 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>启用 JavaScript 的浏览器才能正常运行此页面。</noscript>
下表列出了JApplet在小程序API中添加的有趣方法。它们使您能够访问根窗格提供的功能。您可能会使用的其他方法由Component和Applet类定义。有关常用Component方法的列表,请参阅组件方法,有关使用Applet方法的帮助,请参阅Java小程序。
| 方法 | 用途 |
|---|---|
| void setContentPane(Container) Container getContentPane() |
设置或获取小程序的内容窗格。内容窗格包含小程序的可见GUI组件,并应该是不透明的。 |
| void setRootPane(JRootPane) JRootPane getRootPane() |
创建、设置或获取小程序的根窗格。根窗格管理小程序的内部,包括内容窗格、玻璃窗格等。 |
| void setJMenuBar(JMenuBar) JMenuBar getJMenuBar() |
设置或获取小程序的菜单栏,以管理一组菜单。 |
| void setGlassPane(Component) Component getGlassPane() |
设置或获取小程序的玻璃窗格。您可以使用玻璃窗格拦截鼠标事件。 |
| void setLayeredPane(JLayeredPane) JLayeredPane getLayeredPane() |
设置或获取小程序的分层窗格。您可以使用小程序的分层窗格将组件放在其他组件的上方或下方。 |
这个表格展示了Swing applet的示例以及这些示例的描述。
| 示例 | 描述位置 | 注释 |
|---|---|---|
TumbleItem |
本页 | 一个动画applet |