SWT > コントロール > Shell (Modality, テキスト、イメージ表示など)


org.eclipse.swt.widgets
Class Shell

java.lang.Object 
  extended byorg.eclipse.swt.widgets.Widget 
      extended byorg.eclipse.swt.widgets.Control
          extended byorg.eclipse.swt.widgets.Scrollable
              extended byorg.eclipse.swt.widgets.Composite
                  extended byorg.eclipse.swt.widgets.Canvas
                      extended byorg.eclipse.swt.widgets.Decorations
                          extended byorg.eclipse.swt.widgets.Shell
All Implemented Interfaces:
Drawable




Modality (モダリティ)


Modalityとは同じアプリケーションプログラム内に2つまたはそれ以上のShellがある場合に他 のShellの入力をいっさい受け付けないように設定できるShellの性質のことをいいます。受け付けてもよいようなShell は『modeless』と呼びます。よくありふれているアプリケーションプログラム ではTop Level Shellの多くがmodelessです。Shellでも何も指定しなければmodelessがデフォルトになります。


Shell shell = new Shell(Display display, int style);



親に指定してあるShellからの入力を受け付けたくないときには【SWT.PRIMARY_MODAL】をstyleに指定し、 同じアプリケーション内のShellからの入力を受け付けたくないときには【SWT.APPLICATION_MODAL】 を、デスクトップにあるすべてのアプリケーションからの入力を受け付けたくない場合には 【SWT.SYSTEM_MODALを指定します。









上図に一例を示します。これはtop level shellが『親』ウィンドウのアプリケーションです。『孫』ウィンドウの親は『子ウィンドウ 1』です。孫ウィンドウの立場から考えると 『子ウィンドウ 1』からの入力を受け付けたくない場合は【SWT.PRIMARY_MODAL】をstyleに指定し、アプリケーション内の すべてのShellから入力を受け付けたくない場合は 【SWT.APPLICATION_MODAL】を指定し、このアプリケーションおよび Power PointやExcelといったデスクトップのアプリケーションからの入力を受け付けたく ない場合には【SWT.SYSTEM_MODAL】を指定します。
ここで注意するのは一度Shellをopen( ) してしまうとModalityは途中で変更できないということです。変更するにはShellを隠すまたはdispose( )するしかありません。つまり変更できないということです。
またSWT.PRIMARY_MODAL, SWT.APPLICATION_MODAL, SWT.SYSTEM_MODAL はOSによってはサポートしないものもあるので注意が必要です。




close()とdispose()との違い



クローズボックスボタンをクリックするとclose()メソッドが呼び出される。



SWTではウィジェットはdisposeして破棄することが義務付けられています。 close()メソッドもdipose()メソッドも呼び出されるとShellをdisposeすることには変わりありません。では何が違うのでしょうか? それはclose()メソッドを用いるとShellがdisposeされる前にEventを用いることができ、場合によってはShellを閉じる(破棄する)こと をキャンセルできるということです。これによって例えばクローズボックスをユーザがクリックした場合に『本当に終了しますか?』などの メッセージを入れることができます。dispose()メソッドだと本当に単純にShellをdisposeしてしまいます。また、dispose専用のコントロールを 破棄するときに発生させることができるdisposeイベントというのがありますがこちらはShellを破棄することをキャンセルすることができません。




ToolTip, タイトルのアイコン, タイトルテキストの設定


アプリケーションを作成するならShellのタイトルにテキストやイメージを表示したい場合がほとんどです。Shellのタイトルにテキストを設定するには【setText()】 メソッドを、イメージを表示するには【setImage()】 メソッドを使用します。また、ツールチップを表示する場合には【setToolTip()】 メソッドを使用します。


setText(String string);
Shellのタイトルバーに表示されるテキスト(文字列)をセットします。この引数である文字列には区切り文字(delimeter)やニーモニック(mnemonic)が含むことができません。サポートされていないからです。このメソッドの引数にはnull を使用してはいけません。
String getText();
Shellのタイトルに表示されているテキストを返します。
setImage(Image image);
Shellのためのイメージをセットします。あるWindow Managerではタスクバー中のアイコンとしてこのイメージが使用されます。あるWindow Managerではシステムメニューを起動するボタンのタイトルバーでこのイメージを使用します。Windowsなどのプラットフォームでは[Alt]+[Tab]キーを押したときに表示されるリストのイメージにこのイメージが使用されます。
Image[] getImage();
Shellに使用されているイメージを返します。もしもイメージがセットされていなければnull が返されます。
setImages(Image image);
Shellのためのイメージを複数セットします。空の配列を指定することもできます。複数のイメージをセットすることでタスクバーやタイトルバー、システムメニュー、Alt+Tab リスト、その他のイメージが必要とされるとされる場所で最も適した画像を使用することができます。これらの配列の画像は同じ描写のアイコンでサイズ、depth, 透過性が異なる画像にするのは言うまでもありません。
getImages();
Shellにセットされた複数のイメージの配列を返します。



以下にサンプル例を示します。


ソースの説明
public class Test_shell2 {
 
 public static void main(String[] args) {
  Display display = new Display();
  Shell shell = new Shell(display);
  shell.setText("Shell"); // @

  shell.setImage(new Image(Display.getCurrent(), 
    Object.class.getClass().getResourceAsStream("/icon/icon.gif"))); // A
  shell.setSize(new Point(150, 100)); 
 shell.setToolTipText("ツールチップ"); // B
  shell.open();
  
  while (!shell.isDisposed()) {
    if (!display.readAndDispatch()) {
       display.sleep();
     }
  }
      display.dispose();
 }
}

タイトルのアイコン画像 :  




A Shellのタイトルのアイコンを表示します。
(※ 上のソースコードではTest_shell2.classと同じフォルダにiconというフォルダがありその中にicon.gifが存在するディレクトリ構造になってます。)
@ Shellのタイトルのテキストを表示します
B Shellにツールチップを表示します




Shell 上に図形や文字を描く


Shell クラスはCanvas クラスを継承しているのでShell 上に図形や文字を描くことができます。Canvasクラスのときと同様、GCを使用して図形や文字を描きます。以下にサンプルを示します。このサンプルではGCを使用して3つの楕円と1つの文字をShell上に描いています。






ソースの説明
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class GCTest {
  
  GCTest(){
    Display display = new Display ();
    final Shell shell = new Shell (display);
    shell.setText("Shell");
    shell.addPaintListener(new PaintListener(){
         public void paintControl(PaintEvent e) {
           // shellのクライアント領域を取得
           Rectangle rect = shell.getClientArea();
             // 楕円の図形を描く
           e.gc.setBackground(e.display.
                               getSystemColor(SWT.COLOR_MAGENTA));
         e.gc.fillOval(rect.x, rect.y, rect.width, rect.height);
         e.gc.setBackground(e.display.getSystemColor(SWT.COLOR_CYAN));
         e.gc.fillOval(rect.x+rect.width/4, rect.y+rect.height/4, 
                           rect.width/2, rect.height/2);
         e.gc.setBackground(e.display.getSystemColor(SWT.COLOR_YELLOW));
         e.gc.fillOval(rect.x+rect.width/4+rect.width/8,
                           rect.y+rect.height/4+rect.height/8,
                                          rect.width/4, rect.height/4);
         e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_BLACK));
         // 文字を描く
         e.gc.drawText("まんまる", rect.width/2-15, rect.height/2);
         } 
         });
    
    shell.setSize(250, 200);
    shell.open();
    
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }

    display.dispose ();
  }
    public static void main(String[] args) {
      new GCTest();

  }
}

ソース : GCTest.java




IMEの状態を自動で変更する。


Shell ではIMEの状態を変更するためのメソッドが用意されています。これを使用すれば例えば半角英数のみのテキストの入力画面でユーザが半角英数にIMEを手動で変更しなくても自動で入力できるといったことができます。


setImeInputMode(int mode);
IMEのモードをセットします。modeはSWT.NONE, ROMAN, DBCS, ALPHA, NATIVE, PHONETIC のなかから1つまたはそれ以上のbitwise OR で指定します。
int getImeInputMode();
IMEモードを返します。これはSWT.NONE, ROMAN, DBCS, ALPHA, NATIVE, PHONETIC の中からの1つまたはそれ以上のbitwise OR の結果です。


WindowsXP 日本語 MS-IME 2002の環境のケースでは以下の表のようになります。SWT.DBCS をbitwise OR 指定すると半角文字が全角になります。
(注!: プラットフォームが英語のIMEでこのSWT.DBCSを使用することはできません。リアルなDBCSマシーンでなければならないためです。例えば、日本語のサポート付の英語版WindowsXP ではDBCSは機能しません)。


【表 - IMEの状態 (WindowsXP 日本語 MS-IME2002のケース)】
スタイル定数 IMEの状態 テキストへの入力
SWT.NONE OFF (直接入力)
SWT.PHONETIC 半角カタカナ
SWT.PHONETIC | SWT.DBCS 全角カタカナ
SWT.NATIVE | SWT.DBCS ひらがな
SWT.ALPHA 半角英数
SWT.ALPHA | SWT.DBCS または、 SWT.DBCS のみ 全角英数
SWT.ROMAN 機能しません。 直接入力と同じ。



このメソッドをテキストなどに実装するにはテキストがフォーカスを得たときにこのメソッドが呼び出されるように設定します(以下にサンプルコードを示します)。


Text txt = new Text(shell, SWT.MULTI);
txt.addFocusListener(new FocusAdapter(){
   public void focusGained(FocusEvent e) {
    int style = SWT.NONE; 
    shell.setImeInputMode(style);
    } 
});



やはり本当にIME の切り替えができているかどうかアプリケーションを配布する前にそのアプリを使用するプラットフォームでテストしてみることが重要です。
以下にスタイル定数に応じてテキストのIMEの切り替えができるサンプル例を示します。




ソースの説明
    
import org.eclipse.swt.SWT;                         
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;


public class ImeModeTest {
  
  private int style = SWT.NONE;
  private Button radio1 = null;
  private Button radio2 = null;
  private Button radio3 = null;
  private Button radio4 = null;
  private Button radio5 = null;
  private Button check1 = null;
  private Button check2 = null; 
  
  public ImeModeTest() {
    Display display = new Display();
    final Shell shell = new Shell(display);
    GridLayout grid = new GridLayout();
    grid.marginTop = 10;
    grid.marginLeft = 5;
    grid.marginRight  = 5;
    grid.marginBottom = 10;
    grid.numColumns = 5;
    grid.verticalSpacing = 10;
    grid.horizontalSpacing = 5;
    shell.setLayout(grid);
    shell.setText("IME モードのテスト");
    
    Text text = new Text(shell, SWT.BORDER | SWT.SINGLE);
    GridData data = new GridData();
    data.widthHint = 200;
    data.horizontalSpan = 5;
    text.setLayoutData(data);
    text.setText("");
  
    // ボタンフィールドの作成
    createButtonField(shell);
    
        // IMEの切り替えをtxtに実装
    text.addFocusListener(new FocusAdapter(){
      public void focusGained(FocusEvent e) {
                
        shell.setImeInputMode(checkImeStyle());
        
      }      
    });

    
    shell.pack();
    shell.open();
  
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {

        display.sleep();
      }
    }
    
  
    display.dispose();
  }
  
  // ボタンフィールドの作成のためのメソッド
  private void createButtonField(final Shell shell){
    
    radio1 = new Button(shell, SWT.RADIO);
    radio1.setText("SWT.PHONETIC");
    GridData radio1Data = new GridData();
    radio1Data.horizontalSpan = 1;
    radio1.setLayoutData(radio1Data);
    
    radio2 = new Button(shell, SWT.RADIO);
    radio2.setText("SWT.NATIVE");
    GridData radio2Data = new GridData();
    radio2Data.horizontalSpan = 1;
    radio2.setLayoutData(radio2Data);
    
    radio3 = new Button(shell, SWT.RADIO);
    radio3.setText("SWT.ALPHA");
    GridData radio3Data = new GridData();
    radio3Data.horizontalSpan = 1;
    radio3.setLayoutData(radio3Data);
      
    radio4 = new Button(shell, SWT.RADIO);
    radio4.setText("SWT.NONE");
    GridData radio4Data = new GridData();
    radio4Data.horizontalSpan = 1;
    radio4.setLayoutData(radio4Data);
    radio4.setSelection(true);
    
    radio5 = new Button(shell, SWT.RADIO);
    radio5.setText("SWT.DOCS");
    GridData radio5Data = new GridData();
    radio5Data.horizontalSpan = 1;
    radio5.setLayoutData(radio5Data);
    
    
    check1 = new Button(shell, SWT.CHECK);
    check1.setText("SWT.DBCS");
    GridData  checkData = new GridData();
    checkData.horizontalSpan = 1;
    check1.setLayoutData(checkData);
    
    check2 = new Button(shell, SWT.CHECK);
    check2.setText("SWT.ROMAN");
    GridData  check2Data = new GridData();
    check2Data.horizontalSpan = 1;
    check2.setLayoutData(check2Data);
    
    radio1.addSelectionListener(new SelectionAdapter(){
      public void widgetSelected(SelectionEvent e) {
        if(!radio1.getSelection()) return;
        check1.setEnabled(true);
        check2.setEnabled(true);
        shell.setImeInputMode(checkImeStyle());
      }      
    });
    
    radio2.addSelectionListener(new SelectionAdapter(){
      public void widgetSelected(SelectionEvent e) {
        if(!radio2.getSelection()) return;
        check1.setEnabled(true);
        check2.setEnabled(true);
        shell.setImeInputMode(checkImeStyle());
      }      
    });
    
    radio3.addSelectionListener(new SelectionAdapter(){
      public void widgetSelected(SelectionEvent e) {
        if(!radio3.getSelection()) return;
        check1.setEnabled(true);
        check2.setEnabled(true);
        shell.setImeInputMode(checkImeStyle());
      }      
    });
    
    radio4.addSelectionListener(new SelectionAdapter(){
      public void widgetSelected(SelectionEvent e) {
        if(!radio4.getSelection()) return;
        check1.setSelection(false);
        check2.setSelection(false);
        check1.setEnabled(false);
        check2.setEnabled(false);
        shell.setImeInputMode(checkImeStyle());
      }      
    });
    
    radio5.addSelectionListener(new SelectionAdapter(){
      public void widgetSelected(SelectionEvent e) {
        if(!radio5.getSelection()) return;
        check1.setSelection(false);
        check2.setSelection(false);
        check1.setEnabled(false);
        shell.setImeInputMode(checkImeStyle());
      }      
    });
    
    check1.addSelectionListener(new SelectionAdapter(){
      public void widgetSelected(SelectionEvent e) {
        shell.setImeInputMode(checkImeStyle());
      }      
    });
    

    check2.addSelectionListener(new SelectionAdapter(){
      public void widgetSelected(SelectionEvent e) {
        shell.setImeInputMode(checkImeStyle());
      }      
    });
  }
  
  // ユーザが選択したスタイルを確認するためのメソッド
  private int checkImeStyle(){
    style = SWT.NONE;
    
    boolean foo = (radio1==null) & (radio2==null) &  (radio3==null)
                & (check1==null) &  (check2==null);
    
    if(!foo){
      
    if(radio1.getSelection()){
      style = style | SWT.PHONETIC; 
    }else if(radio2.getSelection()){
      style = style | SWT.NATIVE; 
    }else if(radio3.getSelection()){
      style = style | SWT.ALPHA; 
    }else if(radio5.getSelection()){
      style = style | SWT.DBCS;
    }
    
    
    if(check1.getSelection()){
      style = style | SWT.DBCS; 
    }
    
    if(check2.getSelection()){
      style = style | SWT.ROMAN; 
    }
    
    }
    
    printImeStyle();
    
    return style;
  }
  
  // スタイルビットを標準出力するためのメソッド
  private void printImeStyle(){
    String str = "[スタイルビット]  "+ style + " --- " ;
    
    if(style == SWT.NONE)
      str += ": SWT.NONE ";
    if((style& SWT.PHONETIC)!=0)
      str += ": SWT.PHONTEC ";
    if((style& SWT.NATIVE)!=0)
      str += ": SWT.NATIVE";
    if((style& SWT.ALPHA)!=0)
      str += ": SWT.ALPHA";
    if((style& SWT.DBCS)!=0)
      str += ": SWT.DBCS";
    if((style& SWT.ROMAN)!=0)
      str += ": SWT.ROMAN";

    System.out.println(str);
  }

  

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

ソース : ImeModeTest.java



矩形ではないShellの作成


非常にまれですがアプリケーションのなかには矩形でないShellを用いているプログラムも存在します。SWTではそのようなアプリケーションの窓を作成することができます。それには以下のメソッドを用います。ただしこの場合にはShellのスタイルは SWT.NO_TRIM でなければいけません。

setRigion(Region region);
Shell の形を定義するために使用されるregion をセットします。もしregionがnull であれば、デフォルトの矩形のshellになります。
Region getRegion();
Shell の形を定義するために使用されるregion を返します。もし何もセットされていなければshellが矩形であることを示すnull を返します。

以下にこれを用いたサンプルを示します。このプログラムでは図形上で右クリックするとコンテキストメニューが表示されshellを閉じることができるようになっています。





ソースの説明
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Region;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;


public class NonRectShell {
  private int POINTS = 11;
  private int offsetX = 0;
  private int offsetY = 0;
  
  NonRectShell(){
    Display display = new Display();
    final Point center = new Point(0, 0);
    final int[] radial = new int[POINTS*2];
    final Color color = new Color(display, new RGB(64,196,255));
    
    final Shell shell = new Shell(display, SWT.NO_TRIM);
    shell.setBackground(color);
    shell.setSize(200, 200);
    
    // ここからregionの元になる座標データの配列を計算
    Rectangle bounds = shell.getClientArea();
    center.x = bounds.x + bounds.width/2;
    center.y = bounds.y + bounds.height/2;
    int pos = 0;
    for (int i =0; i< POINTS; ++i){
      double r = Math.PI * 2 *pos/POINTS;
      radial[i*2] = (int)((1+Math.cos(r)) * center.x);
      radial[i*2+1] = (int)((1+Math.sin(r)) * center.x);
      pos = (pos + POINTS / 2) % POINTS;
    }
    
    // shellに表示するためのlanelの作成
    Label label = new Label(shell, SWT.CENTER);
    label.setBackground(color);
    label.setText("へんてこプログラム");
    // labelの大きさを最小の自動計算にする。
    label.pack();
    
     // 右クリックメニューの作成
       Menu menu = new Menu(shell, SWT.POP_UP);
    MenuItem item = new MenuItem(menu, SWT.PUSH);
    item.setText("ウィンドウを閉じる" );
    item.addSelectionListener(new SelectionAdapter(){
      public void widgetSelected(SelectionEvent e) {
        // 窓(shell)を閉じる。
        shell.dispose();
      }
    });

    shell.setMenu(menu);
    
    shell.addMouseListener(new MouseAdapter(){
      public void mouseDown(MouseEvent e) {
        if(e.button ==1){
          offsetX = e.x;
          offsetY = e.y;
        }
      }
    });
    
    shell.addMouseMoveListener(new MouseMoveListener(){
      public void mouseMove(MouseEvent e){
        if((e.stateMask & SWT.BUTTON1) !=0) {
          Point pt = shell.toDisplay(e.x, e.y);
          pt.x -= offsetX;
          pt.y -= offsetY;
          shell.setLocation(pt);
        }
      }      
    });
    
    shell.addKeyListener(new KeyAdapter(){
      public void keyPressed(KeyEvent e) {
        shell.dispose();
      }    
    });
  
    // regionの作成
    Region region = new Region(display);
    region.add(radial);
    region.add(new Rectangle(-5,-5, 150, 25));
    // shellにregionをセット
    shell.setRegion(region);
    shell.open();
  
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {

        display.sleep();
      }
    }
    
    // リソースを食うのでいらなくなったら破棄
    color.dispose(); 
    
    display.dispose();
  }

  

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

ソース : NonRectShell.java






.
Copyright (C) 2006- M.Watanabe All Rights Reserved.