- PR -

SWTに挑戦しようとして・・・

1
投稿者投稿内容
くまぁ
常連さん
会議室デビュー日: 2006/01/26
投稿数: 21
投稿日時: 2006-02-03 09:50
第一歩である何もないウィンドウの表示で躓きました。
下に記載させて頂いている様に、何か特別な処理を埋め
込んだわけでもありません。


//SourceCode**********Start

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class Action2 implements IObjectActionDelegate {

public void setActivePart(IAction action, IWorkbenchPart targetPart) {
}

public void run(IAction action) {
Display display = new Display();
Shell shell = new Shell(display);
shell.open();
}

public void selectionChanged(IAction action, ISelection selection) {
}
}

//SourceCode**********End

実行すると下記のエラーが表示されるのみで、新しい
ウィンドウが作成されませんでした。

【エラーメッセージ】
Unhandled event loop exception
Reason:
Invalid thread access


恐らくSWTを用いるにあたり、基本的なことが抜け落ち
ているという初歩的なミスだと思うのですが・・・。

何故このプログラムが実行されないのか、または、この
エラーの意味等をご存知の方がおられましたら、アドバ
イスを宜しくお願いします。

ハツキタツミ
大ベテラン
会議室デビュー日: 2005/05/24
投稿数: 108
投稿日時: 2006-02-03 10:00
http://www.google.co.jp/search?q=%22Invalid+thread+access+%22&start=0&hl=ja&lr=lang_ja&ie=utf-8&oe=utf-8
くまぁ
常連さん
会議室デビュー日: 2006/01/26
投稿数: 21
投稿日時: 2006-02-03 10:53
ハツキタツミさん、参考資料ありがとうございます。

>SWTは資源の競合が起こらないように、ウィジェット
>の操作を別スレッドから行うこと>を禁止しています。

このような禁止事項があったのですね。
このことを考慮してコードを修正することで、見事
ウィンドウが表示されました。

本当にありがとうございました。


【修正版ソースコード】
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class Action2 implements IObjectActionDelegate {

 public void setActivePart(IAction action, IWorkbenchPart targetPart) {
 }

 public void run(IAction action) {
  MyThread thread1 = new MyThread(1);
  thread1.start();
 }

 public void selectionChanged(IAction action, ISelection selection) {
 }

 class MyThread extends Thread {
  int id;
  public MyThread(int id) {
   this.id = id;
  }
  public void run() {
   Display display = new Display();
   Shell shell = new Shell(display);
   shell.open();
   
   while (!shell.isDisposed()) {
    if (!display.readAndDispatch()) {
     display.sleep();
    }
   }
  display.dispose();
  }
 }
}
NULL
会議室デビュー日: 2005/09/28
投稿数: 4
投稿日時: 2006-02-03 11:35
解決しているようですが、気になることがあるので・・・。

IObjectActionDelegate の run 関数の中でウィンドウの表示処理を記述していると言うことは、すでに別のウィンドウは立ち上がっており、そのウィンドウのメニューなりなんなりに登録された Action2 からウィンドウを立ち上げたいと言うことですよね?

もしそうならば、わざわざ新しいスレッドを立ち上げる必要はありません。

今回のエラーは、1 スレッド 1 Display という原則に触れたから生じたエラーだと思います。
つまり、スレッドにはすでに Display が存在しているので、

Display.getCurrent()

で現在のスレッドに関連づけられた Display が取得できます。
ですので、Display を new している箇所を上記の関数に置き換えるだけで動くようになるはずです。
くまぁ
常連さん
会議室デビュー日: 2006/01/26
投稿数: 21
投稿日時: 2006-02-03 13:50
NULLさん、コメントありがとうございます。

処理の概要を記載していなかったことで、誤解を招いて
しまったようなので記載します。

【処理概要】
ビューウィンドウに表示されているファイルを選択し、
ポップアップメニューの追加項目を選択すると、ウィ
ンドウが表示される。

【getCurrent使用Ver】
public void run() {
 Display display = Display.getCurrent();
 Shell shell = new Shell(display);
 shell.open();

も試してみたのですが、下記のエラーが表示されて
ウィンドウは作成できませんでした。
使い方を間違えているのでしょうか(汗)
これを機会にgetCurrentについて調べてみます。

【エラーコード】
Exception in thread "Thread-1" org.eclipse.swt.SWTException: Invalid thread access
  at org.eclipse.swt.SWT.error(SWT.java:2942)
  at org.eclipse.swt.SWT.error(SWT.java:2865)
  at org.eclipse.swt.SWT.error(SWT.java:2836)
  at org.eclipse.swt.widgets.Widget.error(Widget.java:395)
  at org.eclipse.swt.widgets.Shell.<init>(Shell.java:246)
  at org.eclipse.swt.widgets.Shell.<init>(Shell.java:237)
  at org.eclipse.swt.widgets.Shell.<init>(Shell.java:190)
  at multiBuilder.MakeWindow.run(WindowOperate.java:18)

NULL
会議室デビュー日: 2005/09/28
投稿数: 4
投稿日時: 2006-02-03 17:33
くまぁさん、すいません。
紛らわしい書き方をしてしまいました。
正しいコードとしましては、MyThread の run ではなく、Action2 の run 関数に以下のように書けば出来るようになります。

コード:
public class Action2 implements IObjectActionDelegate { 

  public void run(IAction action) { 
    Display display = Display.getCurrent(); 
    Shell shell = new Shell(display); 
    shell.open(); 
  } 
}



先ほどの投稿時にも書いたように、1 スレッド 1 Display ですが、新しいスレッドでは明示的に作成してあげる必要があります。

エラーが起こった MyThread を使った方法ですと、MyThread スレッドに対応した Display が作成されていませんので、Display.getCurrent() が null を返してしまいます。
null を渡された Shell は Display インスタンスを取得するために、内部で

Display.getCurrent() -> Display.getDefault()

の順で呼び出して有効なインスタンスを取得しようとします。
しかし、Display.getCurrent() で Display が取得できなかった後に呼び出す Display.getDefault() は一番最初に作られた Display(基本的には、メインスレッドの Display)ですのでエラーとなってしまっているのです。

くまぁさんが貼られたエラーコードはそういった経緯で起こったエラーです。
1

スキルアップ/キャリアアップ(JOB@IT)