アプレット


Swingのアプレット

Swing の多くのコンポーネントは、AWT を拡張した軽量コンポーネントです
そのため、多くの場合は AWT の基本的な知識を必要とします

注意しなければいけないのは、AWT を拡張しているとは言え
AWT の重量コンポーネントとは基本的な仕様で異なる部分があります
たとえば、レイアウトや子コンポーネントなどは AWT の考え方と異なります

これらの理由から、AWT に Swing のコンポーネントを使ったり
Swing に AWT のコンポーネントを使うことは好ましくありません
そのようなプログラムをする場合、双方の異なる部分について注意する必要があります

これをふまえて、Swingによるアプレット を作成しましょう
なぜ Swing にもアプレットがあるのかというと、Swing のコンポーネントを配置するためです
やはり Swing のコンポーネントには Swing 仕様のアプレットが好ましいというわけです

Swing は javax.swing というパッケージにあります
このうち、java.applet.Applet に置き換わる Swing のアプレットクラスは
javax.swing.JApplet クラスとしてまとめられています
java.lang.Object
  |
  +--java.awt.Component
        |
        +--java.awt.Container
              |
              +--java.awt.Panel
                    |
                    +--java.applet.Applet
                          |
                          +--javax.swing.JApplet
このクラスは、Applet クラスに加え Swing の基本機能を提供します
Applet 同様にコンストラクタを呼び出す必要はありません(ブラウザが生成します)

public class JApplet extends Applet
implements Accessible, RootPaneContainer

JApplet はAccessibleRootPaneContainer インターフェイスを実装します
Accessible インターフェイスは、ユーザー補助機能を提供する Accessiblility API のものです
この API を Swing のものではないので、この場では紹介しません

RootPaneContainer は javax.swing.JRootPane と呼ばれるクラスと強い関連を持ちます
JRootPane の詳細は後記しますが、このクラスは Swing のある重要な概念の根底です
このクラスには コンテンツペイン と呼ばれるコンテナが含まれています
私たちは、アプレットやアプリケーションに対してコンポーネントを配置したり
レイアウトマネージャーを設定する時はコンテンツペインに追加しなければならない

コンテンツペインの「コンテンツ」とは、ウィンドウに含まれるコンポーネントを指しています
そう、Swing では直接コンポーネントの追加はできないという仕様があるのです
そして、アプレットやアプリケーションはこの JRootPane を唯一含むコンテナなのです
RootPaneContainer インターフェイスはアプレットなどが持つ JRootPane へアクセスする手段なのです
import javax.swing.*;
import java.awt.*;

public class Test extends JApplet {
	public void paint(Graphics g) {
		g.drawString("Kitty on your lap" , 10 , 20);
	}
}


基本的には Applet クラスと扱いが同じように見えますね
JApplet は paint() をオーバーライドしていないので、この手の扱いはお馴染みのものです
ただし、Swing アプレットが持つコンポーネントは JRootPane だけです
直接コンポーネントを追加してはいけないということを忘れないで下さい
(これは、レイアウトマネージャも同様である)

では、Swing のアプレットやアプリケーションにはどのようにコンポーネントを追加するのでしょうか?
そのためには、アプレットのコンテンツペインにアクセスし、これに追加します
JRootPane のコンテンツペインにアクセスするには
RootPaneContainer インターフェイスの getContentPane() メソッドを使用します

public Container getContentPane()

このメソッドは JRootPane が持つコンテンツペインの Container を返します
これにコンポーネントを add() メソッドを使用して追加します
import javax.swing.*;
import java.awt.*;

public class Test extends JApplet {
	public void init() {
		Container contentPane = getContentPane();
		contentPane.add(new Button("Kitty on your lap") , BorderLayout.CENTER);
	}
}


このプログラムでは、Swing アプレットに AWT の重量コンポーネントを追加しています

Swing のもう一つの注意点ですが、JApplet は BorderLayout を使用しています
AWT の Applet クラスは FlowLayout を使用していましたが
Frame クラスが BorderLayout であったため、アプリケーションとの互換に問題があったのです
しかし Swing では JApplet で BorderLayout を使用し、アプリケーションとの連帯に対応しています

Swing でレイアウトマネージャを変更したい場合、コンテンツペインの setLayout() を使用します
アプレットの setLayout() を直接操作すると、例外を発生させます
import javax.swing.*;
import java.awt.*;

public class Test extends JApplet {
	public void init() {
		Container contentPane = getContentPane();
		contentPane.setLayout(new FlowLayout());
		contentPane.add(new Button("Kitty on your lap"));
		contentPane.add(new Button("Tokyo mew mew"));
	}
}
このプログラムを実行すると、背景がコンテンツペインの背景色で描画されます
先ほどの paint() メソッドを使ったプログラムは、super.paint() を呼び出していないので
軽量コンポーネントが描画されなかったために背景が白かったのです
(因みに、Swing で paint() をオーバーライドすることはあまり推奨されない)

また JApplet クラスは addImpl() と setLayout() メソッドをオーバーライドしていますが
これは、Swing はコンポーネントを直接追加することができないという使用を一貫させるため
コンポーネントの追加やレイアウトマネージャを設定しようとすると
オーバーライドされたメソッドは例外を発生させます


JAppletの拡張

コンポーネントの追加を行うと必ず例外が発生すると困ることもある
アプレットが持つ JRootPane クラスをアプレットに追加するときはどうしているのでしょうか?

JApplet コンストラクタは、同クラスの createRootPane() メソッドを呼び出します
このメソッドは protected であり、デフォルトのルートペイン JRootPane を作成します

protected JRootPane createRootPane()

このメソッドは、生成した JRootPane を返します
例えば、このメソッドをオーバーライドして JRootPane の独自の継承クラスを返すこともできます
そして、コンストラクタは同クラス setRootPane() メソッドを呼び出します

protected void setRootPane(JRootPane root)

root には、JApplet のルートペインに設定する JRootPane を指定します
このメソッドは、JApplet が持つルートペインをセットします
JApplet クラスは、プロパティに protected JRootPane rootPane を持ち
このフィールドにパラメータ root を設定します

さて、この時 JRootPane を JApplet のコンテナに追加するのですが
これは、コンテンツペインに追加するのではなくて直接関連付けることになります
この時例外が発生してはミもフタもありません

実は JApplet クラスは、例外発生のスイッチを用意しているのです
それが setRootPaneCheckingEnabled() メソッドです

protected void setRootPaneCheckingEnabled(boolean enabled)

enabled が true ならば、例外チェックを有効にします
最後に呼び出した setRootPaneCheckingEnabled() に true を渡したならば
その後に add() と setLayout() を呼び出すと、例外を発生するようになります

つまり、このメソッドに false を渡した状態ならば追加できるということです
コンストラクタは、JRootPane をアプレットに追加したあとで、例外チェックを ON にしているのです
例外チェックの状態は isRootPaneCheckingEnabled() で可能です

protected boolean isRootPaneCheckingEnabled()

add() と setLayout() を監視している場合は true が返ります
これらのメソッドを直接操作すれば JApplet の継承クラスに
直接コンポーネントを追加するということも可能です(無論、理想に反するが…)
import javax.swing.*;
import java.awt.*;

public class Test extends JApplet {
	public void init() {
		setRootPaneCheckingEnabled(false);
		add(new Button("Kitty on you lap") , BorderLayout.CENTER);
	}
}
こうすると、直接 add() で追加しているにもかかわらず例外は発生しません
もし、setRootPaneCheckingEnabled() を呼び出さずに直接追加した場合は例外が発生します


再描画

もうひとつ、AWT と Swing の大きな違いについて説明します
Swing は AWT と異なり、JApplet やフレームは再描画の時
クライアント領域を背景色で塗りつぶしません

AWT の Applet や Frame クラスのクライアント領域は
Update() が呼び出されると背景色で塗りつぶして初期化しますが
Swing は Update() をオーバーライドし、初期化せずに再描画するようになっています
import javax.swing.*;
import java.awt.*;

public class Test extends JApplet implements Runnable {
	int x = 10;
	public void init() {
		Thread th = new Thread(this);
		th.start();
	}
	public void run() {
		for (; x < 100 ; x++) {
			repaint();
			try {	Thread.sleep(100);	}
			catch(Exception err) {}
		}
	}
	public void paint(Graphics g) {
		g.fillRect(x , 50 , 50 , 50);
	}
}


Applet では、repaint() を呼び出すとこのメソッドが update() を呼び出し
update メソッドがクライアント領域を背景色で塗りつぶしてから paint() を呼び出しました
しかし Swing の JApplet の update() は即座に update() を呼び出すため
このように、以前に描画した fillRect() が残ったまま次の描画が行われます



前のページへ戻る次のページへ