S-JIS[2013-09-26/2015-12-27] 変更履歴

Eclipseプラグイン SWT Composite

Eclipseプラグイン開発SWTのCompositeについて。

 

概要

Compositeは、コンポーネント(ラベルやテキスト等)を配置する為のウィジェット。
ダイアログウィザードページプロパティーページ等でコンポーネントを配置する際に使う。

SWTでは、何らかのコンポーネントを配置したい場合は、自分のCompositeを作ってその中にコンポーネントを配置するのが礼儀。


import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
	@Override
	protected Control createContents(Composite parent) {
		Composite composite = new Composite(parent, SWT.NONE);
		composite.setLayoutData(new GridData(GridData.FILL_BOTH));
		composite.setLayout(new GridLayout(2, false));

		Label label = new Label(composite, SWT.NONE);
		label.setText("ラベル");
		Text text = new Text(composite, SWT.SINGLE);
		text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		text.setText("テキスト");

		return composite;
	}

この例では、渡されたparent(親Composite)に対して新しいCompositeを作り、そこにラベルやテキストを配置している。


まぎらわしいのが、setLayoutData()とsetLayout()。

setLayout()は、自分のCompositeに貼り付けるコンポーネントを、どのように配置するかを指定するもの。
GridLayoutは升目状に配置する。コンストラクターの第1引数で列数(一行に入るコンポーネントの個数)を指定する。
コンポーネントは左上から右へ配置され、一行の個数を超えた分は次の行の左から配置される。

setLayoutData()は、自分(コンポーネント)を貼り付ける先のCompositeに対し、どのように配置するかを指定するもの。
CompositeがGridLayoutの場合はGridDataを指定する。
例えばGridData.FILL_BOTHは上下左右(幅と高さ)を枠いっぱいに広げる、GridData.FILL_HORIZONTALは左右(幅)だけ枠いっぱいに広げる。
上記の例ではラベルが無指定、テキストがFILL_HORAIZONTALなので、ラベルの幅は文字を表示できる最小限になり、テキストの幅はラベルの分を除いてウィンドウいっぱいになる。

つまり、setLayoutData()でどのクラスを指定するのかについては、親CompositeのLayoutがどのクラスになっているかを知らなければならない。
ただしEclipseプラグインでは、親CompositeがGridLayoutで子コンポーネントはGridData、というパターンしか見たことない(笑)

Composite親Compositeに対してGridData.FILL_BOTHを指定しない場合、ウィンドウのサイズを変えたときにCompositeのサイズは変わらない。
FILL_BOTHを指定するということは幅と高さをウィンドウいっぱいに広げるという意味なので、ウィンドウサイズが変わったらそれに追随する。
FILL_BOTHを指定しない場合はComposite内部のコンポーネントからサイズを計算するので、ウィンドウサイズとは無関係になる。

ちなみにFILL_BOTHは、FILL_HORIZONTAL(水平方向(幅)を埋める)とFILL_VERTICAL(垂直方向(高さ)を埋める)を合わせたもの。


GridDataの幅・高さ

GridDataでFILL_BOTH(やFILL_HORIZONTAL・FILL_VERTICAL)を指定した場合、幅や高さはコンポーネントの内容が全て表示されるように計算される。[2015-12-27]
なので、そのGridDataを指定したTextやComboにすごく長い文字列を入れると、コンポーネント(およびそのコンポーネントを含んでいるページ)は画面いっぱいに広がってしまう。
これを回避する為には、GridDataのhintで最大幅・最大高さを指定する。

		Text text = new Text(composite, SWT.BORDER | SWT.MULTI);
		GridData data = new GridData(GridData.FILL_HORIZONTAL);
		data.widthHint = 256;
//		data.heightHint = SWT.DEFAULT;
		text.setLayoutData(data);
		Text text = new Text(composite, SWT.BORDER | SWT.MULTI);
		GridDataFactory.fillDefaults().grab(true, false).hint(256, SWT.DEFAULT).applyTo(text);

動的に変える例

通常、Composite内のコンポーネントの配置は、表示する前に決めた状態から変わることは無い。
(ダイアログをリサイズするとコンポーネントの大きさや位置が変わることはあるが、コンポーネント自体が増減することは無い)

とは言え、コンポーネント自体を入れ替えることも出来る。

import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Widget;
	// 古いコンポーネントを削除
	for (Widget c : composite.getChildren()) {
		c.dispose();
	}

	〜 //compositeに新しいコンポーネントを配置

	composite.layout(); //再描画

Composite#getChildren()で配置されている全コンポーネントを取得し、それぞれのdispose()を呼び出すことによってコンポーネントを破棄する。
そしてCompositeに新しいコンポーネントを配置してから、Composite#layout()を呼び出す。
(layout()を呼び出さないと、表示に反映されない。redraw()というメソッドもあるが、これは関係ないみたい)


SWTへ戻る / Eclipseプラグインへ戻る / Eclipseへ戻る / 技術メモへ戻る
メールの送信先:ひしだま