如果想要两个窗口内同步显示两支证券,那就得让两个浏览器之间能够通信,或者应该说两个applet之间能够通信,java.applet包的AppletContext类提供了getApplet和getApplets方法以获得其它applet的引用,使用这两个方法,Applet能够寻找到其他的Applet并调用它们的方法。不过这是以满足如下安全条件为前提的:
所有Applet位于同一服务器的同一目录。
所有Applet运行在同一页面且位于同一浏览器窗口内。
或许为Applet加上这些安全限制都有着很充分的理由,但第二个条件给我们实现带有Applet到Applet通信功能的多Applet界面带来了限制。所有由于这些Applet位于不同的页面,AppletContext中的Java API无法帮助你完全实现我们的目标。
要实现跨页面Applet到Applet通信首先要满足第一个条件,即如果两个Applet具有相同的codebase,那么即使它们运行在不同的浏览器窗口中,它们也将共享同一个运行时环境。所谓的codebase,我们可以粗略地把它看成Applet所在的服务器目录。
共享运行时环境使得类的静态域和结构能够被所有的Applet实例访问,因此,我们可以用这些静态域和结构在不同的Applet之间传递信息。
我们不仅可以把简单数据类型――比如整数、字符、字符串存储到这些静态域,而且还可以存储Applet实例本身的引用,这样,其他的Applet就可以通过访问这些静态域得到该Applet实例的引用。
假设有两个Applet(AppletA.class和AppletB.class)位于不同的帧,但它们具有相同的codebase。
现在我们要从AppletA里面访问AppletB的公用方法。首先我们要在AppletB里面把它自己的引用保存到一个静态公用域,如:
public class AppletB
{
public static AppletB selfRef = null;
public void init()
{
// 保存当前实例的引用
selfRef = this;
}
...
}
|
现在AppletA可以访问AppletB的实例:
public class AppletA
{
AppletB theOtherApplet = null;
public void callAppletB()
{
// 获得静态域的值,这个静态域保存了AppletB实例的引用
theOtherApplet = AppletB.selfRef;
// 接下来就可以调用AppletB实例 的方法,例如:
theOtherApplet.repaint();
}
...
}
|
这样就实现了两个Applet的通信。由于不同的Applet共享运行时环境,因此即使这些Applet位于不同的页面,这种方法也同样有效。
不过应当注意的是,上面的代码不能处理这种情况:在AppletB没有启动之前就在AppletA里面调用callAppletB方法。如果发生这种情况,则selfRef的值将是null,Applet之间的通信不能正常进行。
当然,我们还可以设计出更加通用的方法。我们可以创建一个类,这个类的用途就是在自己的静态数据结构中保存其他Applet的引用。下面是一个参考实现AppletList。想要让其他Applet访问自己的公用方法的Applet实例首先要在AppletList中注册。按照AppletContext.getApplet(string name)方法的处理模式,每个注册的Applet都和一个字符串相关联。以后当其他Applet需要引用某个Applet实例时,这个字符串就可以作为键(即Applet的标识)使用。
下面是Applet在AppletList中注册的典型过程:
public class AppletA
{
public void start()
{
AppletList.register("Stock-trade-applet", this);
...
}
}
|
其他Applet访问已注册Applet的过程如下:
public class AppletB
{
public void run()
{
AppletA tradeApplet =
(AppletA) AppletList.getApplet("Stock-trade-applet");
...
}
}
|
当Applet结束运行时它必须从ApplietList取消注册:
public void stop()
{
AppletList.remove("Stock-trade-applet");
...
}
|
AppletList类的完整代码如下:
import java.util.*;
import java.applet.Applet;
public class AppletList
{
private static Hashtable applets = new Hashtable();
public static void register(String name, Applet applet)
{
applets.put(name,applet);
}
public static void remove(String name)
{
applets.remove(name);
}
public static Applet getApplet(String name)
{
return (Applet) applets.get(name);
}
public static Enumeration getApplets()
{
return applets.elements();
}
public static int size()
{
return applets.size();
}
}
|
上述的办法是对两个不同的applet类来通信,而我们的目标是让同一个applet类在不同浏览器的同步,即在一支证券在一个浏览器中单步或自动回放,另一支证券要在另一个浏览器窗口中同步单步或自动回放,也就是无论点击任何一个浏览器中的单步或自动按钮,其余的浏览器也要同步回放。
因此,我们也不需要取其它applet的引用了,只要在单步或自动控制逻辑中加入调用从AppletList中取applet全集的函数getApplets,并遍历这些applet,并循环调用单步或自动的控制逻辑就可以了,因为我们并不知道AppletList的HashTable中哪个是第一个打开的窗口,哪个是第二个打开的窗口,那就干脆不管它是第几个,只要HashTable中有几个,那我们就调用这几个applet的控制逻辑。
下面是取applet的全集及循环执行的代码:
Enumeration appletList = AppletList.getApplets();
while(appletList.hasMoreElements())
{
OrderApplet tradeApplet = (OrderApplet)appletList.nextElement();
…… // 控制逻辑
}
|
但一定不能忘了,要在applet的stop方法中加入取消注册的语句,否则如果已经打开三个窗口,中途又关掉一个窗口,AppletList的HashTable中仍有三个applet的引用,与实际数量不符。
如前所述,参与通信的Applet必须具有相同的codebase。此外,如果你运行的是两个不同的浏览器副本且Applet分别运行于这两个浏览器中,由于这些Applet可能没有共享运行时环境(这和浏览器版本、设置有关),因此它们可能不能进行通信。然而,如果你是从同一个浏览器创建出新的浏览器窗口,那么这个问题是不存在的。