2005.11.26

UIスレッドでのタイマー実行

ユーザインタフェースを操作する処理を一定時間ごとに繰り返し行いたい場合,スレッドを使うのが一般的である。しかし,普通に自前で生成したスレッドからはSWTのUIコンポーネントを操作することができないために,DisplayクラスのsyncExec()やasyncExec()を使用する必要がある。ある間隔を持って処理を繰り返し行う場合は,Thread.sleep(500)というようにしてスレッドの実行を停止させることが思いつく方法だが,SWTではOSのタイマーイベントを使用する方法が提供されている。

OSが持つタイマーイベントを利用するには,DisplayクラスのtimerExecメソッドを使用する。

  Runnable runnable = new Runnable() {
    public void run() {
      // 繰り返し行いたい処理
      Display display = ...;
      if (!display.isDispose())
        display.timerExec(500, this);
    }
  };
  Display display = ..;
  if (!display.isDispose())
    display.timerExec(500, runnable);

繰り返し行いたい処理は,Runnableインタフェースの実装として作成する。上記では,匿名クラスとしてRunnableインタフェースの実装オブジェクトを生成している。そして,Displayオブジェクトが破棄されているかどうかをチェックし,破棄されていなければ,DisplayオブジェクトのtimerExecメソッドに時間とRunnableオブジェクトを渡す。第1引数は,Runnableオブジェクトのrunメソッドを呼び出すまでの待ち時間を指定する。上記では,0.5秒後にrunメソッドを呼び出すように指定している。

timerExecメソッドによって,OSにタイマーの登録が行われ,指定時間後にタイマーイベントが発生し,それを契機としてrunメソッドが実行される。ただし,実行されるのは1回だけ。繰り返し処理を行いたい場合は,runメソッド内で再度timerExecメソッドを呼び出して再びrunメソッドが実行されるように登録すればよい。その際に,Displayメソッドが破棄されているかどうかをチェックする必要がある。

このrunメソッドの呼び出しはUIスレッドが行うので,SWTのUIをrunメソッド内で操作することが可能だ。

あるUIコンポーネントを定期的に操作する方法としては,原則として上記のtimerExecメソッドを使用するべきだ。例えば,下記のように自前でスレッドを生成し,その中で繰り返しsyncExecメソッドなどの呼び出しを行ってUIコンポーネントを操作した場合は,他のコンポーネントに影響が発生してしまう。

  Runnable runnable = new Runnable() {
    public void run() {
      while(true) {
        Display display = ..;
        if (!display.isDispose()) {
          display.syncExec(new Runnable() {
            public void run() {
              // 繰り返し処理
            }
          });
        }
        Thread.sleep(500);
      }
    }
  };
  (new Thread(runnable)).start();

上記のようなコードでも,繰り返し処理はちゃんと実行されるだろう。しかし,DirectoryDialogクラスを利用して実現されるディレクトリ選択ダイアログの動作が,正しく行われなくなってしまう。具体的には,サブディレクトリやアイコンの読み込みがマルチスレッド化されているのだが,そのスレッドが動作しなくなってしまい,ディレクトリの選択ができないといった現象になる。

気軽にスレッドを作ることはできるが,その結果思わぬ不具合を引き起こしてしまう可能性があるので,気をつけて欲しい。

| | コメント (16) | トラックバック (1)

2005.11.24

ステータスバーへのコンポーネント登録と削除

ステータスバーへのアイコン登録

今回は,Eclipseのワークベンチウィンドウに配置されているステータスバーへアイコン表示コンポーネントを登録する方法を紹介する。アイコンはSWTのLabelコンポーネントを使うので,実質上はSWTコンポーネントのステータスバーへの登録方法となる。

まず,普通にエディタがアクティブなときのステータスバーを見てみると,以下のような感じになっている。

status0

編集モードやキャレットの位置などが,セパレータで区切られて表示されている。もちろん,自分のプラグインの領域を確保したいので,セパレータの登録も是非やっておきたい一つだろう。

まずはワークベンチウィンドウから,ステータスバーマネージャを取得する。この方法は,「ステータスバーへのアクセス」で紹介した手順で行えばよい。基本的には,得られたIStatusLineManagerオブジェクトのaddメソッドを使って,コンポーネントやアクションをステータスバーに登録する。例えば,アクションを登録するには以下のような感じになる。

  IStatusLineManager manager = ...; // ステータスバーオブジェクトの取得
  manager.add(new Action("アクション") {});

status1

SWTのコンポーネントをステータスバーに登録するためには,IContributionItemインタフェースを実装したクラスのオブジェクトが必要となるが,ControlContributionクラスを使用することが一般的だろう。

  manager.add(new ControlContribution("my_id") {
    protected Control createControl(Composite parent) {
      new Label(parent, SWT.SEPARATOR); // セパレータの登録
      Label l = new Label(parent, SWT.NONE); // アイコンの登録
      ImageDescriptor desc = ...;
      l.setImage(desc.createImage());
      return parent;
    }
  });

登録するIContributionItemオブジェクトには,IDが必要となる。このIDは,ステータスバーからオブジェクトを取得したり削除する際に使用できる。上記では,ControlContributionクラスのコンストラクタにIDを渡している。

セパレータは,Labelクラスのコンストラクタの第2引数にSWT.SEPARATORを渡すことで登録できる。上記の例では,その後にイメージを持つLabelオブジェクトを登録している。createControlメソッドに渡されるCompositeオブジェクトは,レイアウトとしてStatusLine$StatusLineLayoutクラスが適用されていて,コンポーネントの生成順に左から配置してくれるようになっている。

これを実行すると,以下のような感じになる。アイコンは,IP Messengerのものを使用してみた。

status2

登録したIContributionItemオブジェクトを削除するためには,以下のようにすればよい。

  IContributionItem item = manager.find("my_id");
  manager.remove(item);
  manager.update(true);

findメソッドにIDを渡してIContributionItemオブジェクトを取得し,それをremoveメソッドに渡して削除する。その後,updateメソッドを呼び出して,削除したことをステータスバーの表示に反映させる。

上記のIContributionItem系の扱いは,ツールバーやメニューバーに関しても同じなので,覚えておくと応用が利くだろう。

| | コメント (0) | トラックバック (0)

2005.11.22

ステータスバーへのアクセス

Eclipseの最下部には,いろんな情報を通知してくれるステータスバーが位置している。自作プラグインから,このステータスバーを利用したいと思うことも多いだろう。今回は,Eclipseのステータスバーへアクセスするための方法を紹介する。

statusbar

Eclipseの下部に配置されているステータスバーは,状況依存のステータスバーである。つまり,状況によって表示される内容が異なるということだ。ここで言う状況とは,ワークベンチ内で何が選択されているか,という状況である。例えばテキストエディタがアクティブになれば,編集属性やキャレットの位置が表示されるし,アウトラインビューがアクティブになれば,アウトラインに関する情報に表示が切り替わる。表示できる領域は限られているので,今どこに着目しているかによって表示が限定されるということだ。

ステータスバーを管理しているオブジェクトは,IStatusLineManagerインタフェースで表される。「ワークベンチウィンドウに張り付いているんだから,IWorkbenchWindowインタフェースに取得メソッドがあるんじゃないの?」と思ってしまうが,そんなに簡単ではない。なぜなら,状況依存という特徴があるからだ。

まずは,特定のViewに依存するステータスバーオブジェクトの取得方法から紹介しよう。ViewPartクラスのサブクラス内で,以下のようにすればステータスバーオブジェクトを得ることができる。

  IViewSite viewSite = getViewSite();
  IActionBars actionBars = viewSite.getActionBars();
  IStatusLineManager manager = actionBars.getStatusLineManager();

このmanagerオブジェクトに対してコンポーネントやアクションを登録することで,そのViewに特化したステータスバーに登録することができる。もちろん状況依存なので,managerに登録されたコンポーネントやアクションは,そのViewがアクティブになったときにしか表示されない。

次は,特定のEditorに依存するステータスバーオブジェクトの取得方法を紹介する。EditorPartクラスのサブクラス内で,以下のようにすればステータスバーオブジェクトを得ることができる。

  IEditorSite editorSite = getEditorSite();
  IActionBars actionBars = editorSite.getActionBars();
  IStatusLineManager manager = actionBars.getStatusLineManager();

このmanagerオブジェクトに対してコンポーネントやアクションを登録することで,そのEditorに特化したステータスバーに登録することができる。もちろん状況依存なので,managerに登録されたコンポーネントやアクションは,そのEditorがアクティブになったときにしか表示されない。

さて,上記の方法では,特定のViewやEditorがアクティブにならなければ,せっかく登録したコンポーネントやアクションが表示されない。時には状況に依存せずに常にコンポーネントやアクションをステータスバーに表示させておきたいこともあるだろう。状況非依存のステータスバーオブジェクトを得る方法があるのだが,Eclipse的には反則気味なやり方になる。internalパッケージのクラスを利用しなければならないからだ。

  WorkbenchWindow workbenchWindow = (WorkbenchWindow)getSite().getWorkbenchWindow();
  IActionBars actionBars = workbenchWindow.getActionBars();
  IStatusLineManager manager = actionBars.getStatusLineManager();

WorkbenchPartクラス(ViewPartやEditorPartの親)のサブクラス内で上記の処理を行うことによって,状況非依存のステータスバーのオブジェクトを得ることができる。このmanagerオブジェクトに対してコンポーネントやアクションを登録することで,ViewやEditorの選択状態に関わらず,常にコンポーネントやアクションが表示されるようになる。

ただでさえ狭い領域なので,ステータスバーにはむやみに常に表示されてしまうようなコンポーネントやアクションを登録するべきではない。internalパッケージにしか取得メソッドが存在しないのは,推奨できない方法なんだというメッセージが含まれているのだろう。よほど特殊な場合でなければ状況依存の方法を採用し,どうしてもという時は,16x16のアイコンの登録くらいに押さえておくようにすべきだろう。

| | コメント (0) | トラックバック (0)

2005.10.14

Contributing to Eclipse本のサンプルコード

「Eclipseプラグイン開発を行うなら,まずはこれを読め!」という濃い内容の「Contributing to Eclipse」本,これに掲載されているソースコードのダウンロード元をいつも忘れてしまうので,メモしておく。

Eclipseプラグイン開発(Contributing to eclipse)
http://www.asahi-net.or.jp/~yf8k-kbys/eclipse.html

上記は訳本の紹介サイトだけど,ソースコードは基本そのまんまなので有効である。

| | コメント (0) | トラックバック (0)

2005.10.01

sourceforge.jpはじめました(ipmsg4e)

IP Messenger for Eclipseの開発を進めるにあたって,やはり「オープン」であることが大事かなと思い,sourceforge.jpにてソースコードやトラッキングなどの情報を,一般に公開することにした。

[IP Messenger for Eclipse(ipmsg4e) : sourceforge.jp]
https://sourceforge.jp/projects/ipmsg4e/

もちろんこのブログ内でもエントリは続けていくが,このブログはあくまで「プラグイン開発のための情報」をエントリしていきたいので,ipmsg4eについてのことは上記の場所で行っていくことにする。

もし要望などのご意見があれば,上記のフォーラムなどでどんどん連絡してほしい。

| | コメント (5) | トラックバック (0)

«早速バグ発見(IPMessengerプラグイン:コア)