依頼人は金持ちだ!〜リッチクライアントに挑む

SWT の Browser ウィジット

さて、じゃあ問題の Browser クラスである。コイツの単純な使い方は、SWT が判ってりゃチョチョイのチョイで使えるものである。単純に Browser クラスを使うだけならこんなもんだ。

import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;

public class SimpleBrowser implements LocationListener {
     private String default_url = "http://localhost/";
     private String TopURL;       /* 最初にアクセスするURL */
     private String theQuitURL;   /* このURLに来たら終了する */
     private boolean end_flag = false;

     private Shell shell;         /* フレーム */
     private Browser browser;     /* 例の Browser ウィジット */

     public static void main( String [] args ) {
          new SimpleBrowser( args );
     }

     public SimpleBrowser( String [] args ) {
          if( args.length < 1 ) {
               System.out.println( "java -classpath .;swt.jar SimpleBroser  []" );
               System.exit( 1 );
          } else if( args.length == 1 ) {
               default_url = args[0];
               theQuitURL = "";
          } else {
               default_url = args[0];
               theQuitURL = args[1];
          }
          
          /* 常識的な SWT プログラミング */
          Display d = new Display();
          shell = new Shell(d);
          shell.setText( "対戦型五目並べ" );
          FillLayout layout = new FillLayout( SWT.VERTICAL );
          shell.setLayout(layout);

          /* Browser ウィジットを生成 */
          browser = new Browser( shell, SWT.NONE );
          if( args.length > 0 ) {
               TopURL = args[0];
          } else {
               TopURL = default_url;
          }
          /* 最初のページを表示 */
          browser.setUrl( TopURL );

          /* ページを切り替えた時にコールバックを呼び出すようにする */
          browser.addLocationListener( this );

          /* 常識的なイベントループ */
          shell.open();
          while( ! shell.isDisposed() ) {
               if( end_flag ) {  /* 終了させるために */
                    break;
               }
               if( ! d.readAndDispatch() ) {
                    d.sleep();
               }
          }
          d.dispose();
     }

     /* LocationListener: ページ切り替わりの表示前に呼ばれる */
     public void changing(LocationEvent event) {
          if( event.location.equals( theQuitURL ) ) {
               end_flag = true;
          }
     }

     /* LocationListener: ページ切り替わりの表示後に呼ばれる */
     public void changed(LocationEvent event) {
     }
}

はい、簡単だね。これが簡単じゃない人は、本を買って読みたまえ。だから、意外に簡単にブラウザ機能が実現できてしまうわけだ。しかも、余計なボタンとかが一切無いので、「戻る」ボタンを押されたらどうしよう???とかなる余地がないのである! 「リッチクライアント」の場合には結構ファシスト的に「こうしろ!」とフローを強制できる、というメリットがあるのだ。

あコンパイル&実行はこんなところでできる。なんせ SWT はネイティブライブラリを使い倒すものなので、Windows の場合は実行ディレクトリに swt-win32-3063.dll というようなDLLがないとダメだ。で、当然 swt.jar にクラスパスを通して、

C:\> javac -classpath .;swt.jar SimpleBrowser.java
C:\> java -classpath .;swt.jar SimpleBrowser http://localhost/

という具合に起動できる。お姿はこんなもんだ。まあ、こりゃ Apache のデフォルトのトップページだな。

後々のこともあるので、ここで SWT が必要とするファイルについて、ちょっとだけまとめておくぞ。

実際のプログラムを固めた jar ファイル
説明不要。
swt.jar
SWT のライブラリが固めてある jar ファイル。Eclipse とかに付いてくるし、独立でダウンロードしてもOK。
swt-win32-3063.dll
SWT が使うネイティブ・ライブラリ。勿論プラットフォームが違えば名前が違う。まあ、こういうネタは Window でやっておくのが無難なので、そうしているだけだ。こいつも Eclipse とかに付いてくるし、swt.jar と一緒に独立でダウンロードしても、Windows 版を選べばついてくる。で、コイツは後でやはり jar に固める..なんてこともする。その時には swtwin.jar とかいう名前にする。

さて、じゃあ今見た Browser クラスを使って、「五目並べ対戦システム」のブラウザ部分を作っていこう。とはいえ、いくつか注意しなくてはならないことがある。その注意点の本質は次のことだ。

Browser クラスは、そのプラットフォームで使いやすいブラウザのライブラリをただ単に呼び出している、というだけのものである。言い換えると、Windows ならば Internet Explorer を使うわけであり、あらゆるIE の問題点を、Browser クラスは引き継ぐ

なので実は次のような問題が発生することを、あらかじめ注意しておく。

  1. IE はローカルアクセスに関しては、セキュリティ関連プロパティを設定するのを拒んでいる。言い換えると、ローカル環境でテストする場合には、クッキーを無効化できない。これが引き起こす問題点については、「Struts による五目並べ対戦システムセッションって一体何なの?」を熟読のこと。結論だけ言えば、ローカル環境でテストする場合には、一台は SWT のBrowserクラスを使ったリッチクライアント(つうかIE)、もう一台(対戦相手)はネスケを使ってアプレットでテストするのが、一番問題がない。

  2. どうやら SWT の Browser クラスは、たとえ

    [ツール]→[インターネットオプション]→[インターネット一時ファイル]→[設定]

    で、「ページを表示するごとに確認する」を選択してキャッシュを使わずに常にアクセス元に読みに行かせるようにしても、「とりあえずキャッシュを使おう!」とする。結果、凄いお馬鹿な話で、一部の動作がキャッシュのせいで重複する。まあ、「Front Controller」で Struts の側が全部 /gomoku/show.do で処理をしている、というのがちょっと引っかかってしまるのである。対戦後に結果を表示しようとすると、ひょっとしてもう一度実対戦ウィンドウを開こうとするかもしれんが、これはそういうお馬鹿仕様が原因である。
    (ちなみに java.applet.Applet.showDocument() メソッドも、すでにキャッシュにある限り、「インターネットオプション」の設定ではなくてキャッシュを優先してしまう...困ったもんだ)

  3. SWT の Browser クラスでは、本質的に「今読んだ HTML ファイルの内容」を取得することができない。内容を表示してくれるが、その内容にアクセスできないんである...これはハッキリ言って困った(ブラウザと自前の対戦ウィンドウ・クラスが連携できない)。が、これはちょっとトンチで解決したのでお楽しみに。

  4. 実際にHTMLサーバにアクセスするのは、どうせOS側のライブラリなので、サーバ側ではそれが「ブラウザから」なのか「SWT Browserクラス(リッチクライアント)から」のアクセスなのか、判定する手段がない。言い換えると「ブラウザ」と「リッチクライアント」と両方のタイプのクライアントを受け付けて、場合分けをすることは本質的に不可能である。

....という具合に、

こいつぁまだ途上だ!

というのが正直な感想である。ぜひぜひ Eclipse & SWT の開発者の皆さん、頑張ってくれ。さすがにメジャーなオープンソース・プロジェクトが文句をつけるんなら、アノM$だって少しは言うこと聞いてくれるだろうね。



copyright by K.Sugiura, 1996-2006