[PR]泌宿斣慻昞
崱栭偺斣慻联


Understanding Layouts in SWT

Understanding Layouts in SWT 泣塑胳条

Copyright (c) 2001 Object Technology International, Inc.

Eclipse Corner Article

妥腆

SWT を蝗ってアプリケ〖ションを今く狠に、ウィンドウに泼魔ある嘲囱を积たせるためにレイアウトを蝗う涩妥があるかもしれません。レイアウトは Composite の灰妥燎であるウィジットの疤弥とサイズを拎侯します。レイアウトクラスは藐据クラス Layout のサブクラスです。この淡祸では、どのように筛洁レイアウトを蝗うか、どのように迫极レイアウトクラスを侯るかということを疽拆します。

By Carolyn MacLeod, OTI

March 22, 2001

Revised by Shantha Ramachandran, OTI

May 02, 2002

泣塑胳条 joesaisan

March 30, 2004 付矢は http://www.eclipse.org/articles/Understanding%20Layouts/Understanding%20Layouts.htm にあります。疙条の回纽霹は mailto:joesaisan@hotmail.com までお搓いします。

レイアウト

车囱

SWT を蝗ってアプリケ〖ションを今く狠に、ウィンドウに泼魔ある嘲囱を积たせるためにレイアウトを蝗う涩妥があるかもしれません。レイアウトは Composite*1 の灰妥燎であるウィジットの疤弥とサイズを拎侯します。レイアウトクラスは藐据クラス Layout のサブクラスです。この淡祸では、どのように筛洁レイアウトを蝗うか、どのように迫极レイアウトクラスを侯るかということを疽拆します。

SWT では疤弥疯めとサイズ圭わせは极瓢弄に乖われません。アプリケ〖ションは介袋步の檬超で、あるいはリサイズリスナ〖の面で Composite 惧の灰ウィジットのサイズと疤弥を疯めることができます。もし灰ウィジットにサイズが涂えられなければ、それらはサイズ 0 となり山绩されません。

布哭において、レイアウトの的侠の狠に蝗う办忍弄な脱胳を棱汤します。Composite (ここでは TabFolder) は疤弥 (location)、クライアントエリア (clientArea)、トリム (trim) を积ちます。この Composite は钨票晃の疤弥に弥かれた企つの灰ウィジットを积っています。レイアウトによって、この灰ウィジットのサイズと疤弥を瓷妄します。このレイアウトでは灰票 晃のスペ〖シングの拇泪と、灰ウィジットとレイアウト链挛の先とのマ〖ジンを拇泪をすることができます。レイアウト极挛のサイズは、Composite のクライアントエリアのサイズと票霹です。

image001.png

ウィジットにおいて庭黎されるサイズとは、その柒推を山绩するのに呵你嘎涩妥なだけの络きさのことです。惧哭の Composite では、庭黎されるサイズは灰ウィジット链てを崔む办戎井さな煌逞妨になります。灰ウィジットがアプリケ〖ションによって疤弥疯めをされた眷圭、 Composite は灰ウィジットのサイズと疤弥をもとに极尸の庭黎されるサイズを纷换します。疤弥疯めをするようなレイアウトのクラスを Composite が蝗った眷圭、レイアウトに极咳のクライアントエリアのサイズを纷换させ、そこにトリムを裁えて、庭黎されるサイズを疯年します。

筛洁レイアウト

SWT ライブラリでの筛洁のレイアウトには肌のものがあります。

  • FillLayout - 票办サイズのウィジットを帽办の乖、あるいは误に芹弥します。
  • RowLayout - ウィジットを乖で芹弥します。fill, wrap, spacing といったオプションがあります。
  • GridLayout - ウィジットをグリッド (呈灰) 觉に芹弥します。
  • FormLayout *New in 2.0* - ウィジットの娄烫にアタッチメントを侯ることによって芹弥します。

筛洁レイアウトを蝗うためには、SWT レイアウトパッケ〖ジをインポ〖トする涩妥があります。

import org.eclipse.swt.layout.*;

レイアウトは汗しこむものです。Composite にレイアウトをセットするには、ウィジットの setLayout(Layout) メソッドを蝗ってください。肌のコ〖ドでは、Shell*2 ( Composite のサブクラス) はその灰ウィジットを RowLayout を蝗って疤弥疯めするように回年されています。

Shell shell = new Shell();
shell.setLayout(new RowLayout());

レイアウトクラスには滦炳するレイアウトデ〖タクラスがある眷圭があります。レイアウトデ〖タクラスは、Object のサブクラスであり、泼年の灰ウィジットに滦するレイアウトデ〖タを积っています。捶浆により、レイアウトデ〖タクラスはレイアウトクラス叹の Layout を Data で弥き垂えたものになります。毋えば、筛洁弄なレイアウトクラスである RowLayout は RowData と钙ばれるレイアウトデ〖タクラスを积ち、GridLayout は GridData を、FormLayout は FormData を积っています。ウィジットへレイアウトデ〖タクラスをセットするには肌のようにします。

Button button = new Button(shell, SWT.PUSH);
button.setLayoutData(new RowData(50, 40));

この矢今での毋

この矢今にあるスナップショットのほとんどは、笆布のコ〖ド毋をいろいろと恃妨し、悸乖した冯蔡から唬られています。レイアウトのタイプ、蝗脱するオプション、灰ウィジットのタイプや改眶を恃えるわけです。

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;

public class LayoutExample {
  public static void main(String[] args) {
      Display display = new Display();
      Shell shell = new Shell(display);
      // レイアウトを栏喇する。
      RowLayout layout = new RowLayout();
      // フィ〖ルドを努碰に肋年する。
      layout.wrap = true;
      // Composite にセットする。
      shell.setLayout(layout);
      // 灰ウィジットを栏喇する。
      new Button(shell, SWT.PUSH).setText("B1");
      new Button(shell, SWT.PUSH).setText("Wide Button 2");
      new Button(shell, SWT.PUSH).setText("Button 3");
      shell.pack();
      shell.open();
      while (!shell.isDisposed()) {
         if (!display.readAndDispatch()) display.sleep();
      }
  }
}

惧のコ〖ドを悸乖すると、肌のようになります。

image004.jpg

ユ〖ザ〖が Shell をリサイズし、Button 3 の箭まるスペ〖スがなくなると、RowLayout は Button 3 をこのように肌の乖に流ります。

image006.jpg

笆惧のように、レイアウトの蝗脱はリサイズと泰儡に簇わっています。ですからこの矢今では、ほとんどの毋で Composite を络きくしたり井さくしたりするとどうなるかを绩しています。Layout がどのように怠墙するのかを棱汤するためです。

FillLayout

FillLayout は呵もシンプルなレイアウトクラスです。链てのウィジットを帽办の乖、あるいは误に芹弥し、それらのサイズを动扩弄に票じにします。介袋步箕に链てのウィジットはその面で办戎升弓いもの、办戎光いものと票办サイズになります。FillLayout はウィジットを肌の乖に流りませんし、マ〖ジンやスペ〖シングを回年することもできません。タスクバ〖やツ〖ルバ〖、Group 柒にチェックボックスを姥み脚ねるのにこのレイアウトが蝗えるかもしれません。あるいは、FillLayout は Composite がたった办つしか灰を积たないときにも蝗えます。毋えば、Shell が Group を办つ积つとき、FillLayout を蝗って Group を Shell 链挛に窗链に弓げることができます。

ここにコ〖ド毋の办婶があります。呵介に FillLayout を栏喇し、それから (ここでは库木なものが瓦しいので) type フィ〖ルドを SWT.VERTICAL に、レイアウトを Composite (ここでは Shell) にセットします。Shell には灰ウィジット 3 つとして病しボタン B1, B2, Button 3 があります。FillLayout では灰ウィジットは撅に票办のサイズであり、蝗える眷疥は链て蝗うということに庙罢してください。

FillLayout fillLayout = new FillLayout();
fillLayout.type = SWT.VERTICAL;
shell.setLayout(fillLayout);
new Button(shell, SWT.PUSH).setText("B1");
new Button(shell, SWT.PUSH).setText("Wide Button 2");
new Button(shell, SWT.PUSH).setText("Button 3");

肌の山で FillLayout の垮士と库木の般いと、介袋步箕と科ウィジットを络きくした箕にどうなるかを绩します。

介袋步箕 リサイズ稿
fillLayout.type = SWT.HORIZONTAL (デフォルト) image008.jpg image010.jpg
fillLayout.type = SWT.VERTICAL image012.jpg image014.jpg

RowLayout

RowLayout は FillLayout よりもう警し办忍弄に蝗われています。なぜならウィジットの乖流りができ、マ〖ジンとスペ〖シングを肋年することができるからです。RowLayout には肋年できるフィ〖ルドがたくさんあります。さらに、RowLayout 惧の称ウィジットの光さと升は、RowData オブジェクトを setLayoutData メソッドを蝗ってセットすることで回年することができます。

RowLayout 肋年材墙フィ〖ルド

Type *New in 2.0*

type フィ〖ルドを蝗って RowLayout が垮士な乖と库木な误のどちらにウィジットを芹弥するか疯めることが叫丸ます。RowLayout では垮士がデフォルトです。

Wrap

wrap フィ〖ルドを蝗って RowLayout 惧のウィジットが附哼の乖で狸めるスペ〖スが痰くなったときにウィジットを肌の乖に流るかどうか疯めることが叫丸ます。RowLayout はデフォルトで乖流り (wrap) します。

Pack

pack フィ〖ルドが true の箕、RowLayout 惧のウィジットはそれぞれ极脸なサイズをとり、できるだけ焊娄に事べられます。pack が false の箕、ウィジットは FillLayout でのウィジットと票じように、蝗える眷疥は链て蝗うよう弓がります。RowLayout はデフォルトで pack します。

Justify

justify フィ〖ルドが true の箕、RowLayout 惧のウィジットは焊宝にできるだけ欢らばります。科 Composite が络きくなって途尸なスペ〖スができた眷圭、そのスペ〖スはウィジット粗に堆霹に尸充されて芹弥されます。pack と justify の尉数が true の眷圭、ウィジットはそれぞれ极脸なサイズをとり、途尸なスペ〖スはウィジットが窗链に焊宝に欢るように芹弥されます。デフォルトでは RowLayout は justify しません。

MarginLeft, MarginTop, MarginRight, MarginBottom そして Spacing

これらのフィ〖ルドを蝗ってウィジット粗のスペ〖シングや、ウィジットとその科 Composite とのマ〖ジンをピクセルで肋年することができます。RowLayout のデフォルトでは、マ〖ジンとスペ〖シングは 3 ピクセルに肋年されています。マ〖ジンとスペ〖シングの挝拌は肌の哭に绩します。

image016.jpg

RowLayout の毋

肌のコ〖ド毋では RowLayout を栏喇し、链てのフィ〖ルドをデフォルトと佰なる猛にしてから、Shell にセットしています。

RowLayout rowLayout = new RowLayout();
rowLayout.wrap = false;
rowLayout.pack = false;
rowLayout.justify = true;
rowLayout.type = SWT.VERTICAL;
rowLayout.marginLeft = 5;
rowLayout.marginTop = 5;
rowLayout.marginRight = 5;
rowLayout.marginBottom = 5;
rowLayout.spacing = 0;
shell.setLayout(rowLayout);

デフォルトの猛を蝗う眷圭は肌の办乖を今くだけです。

shell.setLayout(new RowLayout());

布の山でフィ〖ルドを回年した冯蔡を绩します。

介袋步箕 リサイズ稿
wrap = true;pack = true;justify = false;type = SWT.HORIZONTAL (デフォルト) image018.jpg image020.jpg
wrap = false (スペ〖スがない眷圭磊り艰り) image021.jpg image023.jpg
pack = false (链て票办サイズ) image025.jpg image027.jpg
justify = true (できるだけ欢らばる) image029.jpg image031.jpg
type = SWT.VERTICAL (侥の误に芹弥される) image033.jpg image035.jpg

RowLayout で RowData オブジェクトを蝗う

RowLayout 惧のウィジットはそれぞれに RowData オブジェクトをセットすることで、介袋步箕の光さと升を回年することができます。肌のコ〖ドでは、Shell 惧の Button の介袋步箕のサイズを RowData を蝗って恃构しています。

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;

public class RowDataExample {
  public static void main(String[] args) {
      Display display = new Display();
      Shell shell = new Shell(display);
      shell.setLayout(new RowLayout());
      Button button1 = new Button(shell, SWT.PUSH);
      button1.setText("Button 1");
      button1.setLayoutData(new RowData(50, 40));
      Button button2 = new Button(shell, SWT.PUSH);
      button2.setText("Button 2");
      button2.setLayoutData(new RowData(50, 30));
      Button button3 = new Button(shell, SWT.PUSH);
      button3.setText("Button 3");
      button3.setLayoutData(new RowData(50, 20));
      shell.pack();
      shell.open();
      while (!shell.isDisposed()) {
         if (!display.readAndDispatch()) display.sleep();
      }
  }
}

これがこのコ〖ドを悸乖した冯蔡です。

image037.jpg

GridLayout

GridLayout はおそらく办戎蝗い尽缄のいい、动蜗な筛洁レイアウトでしょう。しかし、このレイアウトは办戎剩花なものでもあるのです。GridLayout では灰ウィジットは呈灰觉に芹弥されます。また、たくさんのフィ〖ルドを肋年でき、RowLayout と票じように GridData と钙ばれるレイアウトデ〖タオブジェクトをウィジットに簇息烧けることができます。GridLayout が动蜗なのは、GridLayout 惧のウィジットのレイアウトを GridData で瓷妄できるところにあります。

GridLayout 肋年材墙フィ〖ルド

NumColumns

numColumns フィ〖ルドは GridLayout で呵も脚妥なフィ〖ルドであり、たいていの眷圭办戎呵介に肋年されるフィ〖ルドです。ウィジットは侥の误ごとに焊から宝へと芹弥されますが、糠しい乖は numColumns + 1 つ誊のウィジットが纳裁されたときに栏喇されます。デフォルトでは侥の误 1 つしかありません。肌のコ〖ドでは 5 つの Button を屯」な升で积つ Shell を栏喇し、それらを GridLayout で瓷妄しています。その肌の山で numColumns を 1, 2, 3 に肋年した GridLayout を绩します。

Display display = new Display();
Shell shell = new Shell(display);
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 3;
shell.setLayout(gridLayout);
new Button(shell, SWT.PUSH).setText("B1");
new Button(shell, SWT.PUSH).setText("Wide Button 2");
new Button(shell, SWT.PUSH).setText("Button 3");
new Button(shell, SWT.PUSH).setText("B4");
new Button(shell, SWT.PUSH).setText("Button 5");
shell.pack();
shell.open();
while (!shell.isDisposed()) {
   if (!display.readAndDispatch()) display.sleep();
}
numColumns = 1 numColumns = 2 numColumns = 3
image039.jpg image041.jpg image043.jpg
MakeColumnsEqualWidth

makeColumnsEqualWidth フィ〖ルドを蝗うと、动扩弄に误を票じ升に路えます。デフォルトでは false です。惧の毋で误の眶を 3 にし、升を路えるよう肋年すると布哭のものが评られます (稿で揭べるような泼侍な回年をしない嘎り、ウィジットは误の焊に路えられます)。

image045.jpg

MarginWidth, MarginHeight, HorizontalSpacing そして VerticalSpacing

GridLayout でのマ〖ジンとスペ〖シングの挝拌は RowLayout と票じです。般いは焊宝のマ〖ジンは marginWidth にグル〖プ步され、惧布のマ〖ジンは marginHeight にグル〖プ步されているということです。さらに RowLayout でのスペ〖シングは RowLayout のタイプに巴赂していましたが、GridLayout では horizontalSpacing と verticalSpacing をそれぞれ侍」に肋年できます。

GridData オブジェクトのフィ〖ルド

GridData は GridLayout に簇息烧けられたレイアウトデ〖タオブジェクトです。GridData オブジェクトをウィジットにセットするには setLayoutData メソッドを蝗います。毋えば、Button に GridData をセットする眷圭、布淡のようにします。

Button button1 = new Button(shell, SWT.PUSH);
button1.setText("B1");
button1.setLayoutData(new GridData());

もちろんこのコ〖ドは帽にフィ〖ルドが链てデフォルト猛の GridData オブジェクトを栏喇しただけであり、レイアウトデ〖タを部もセットしていないのと票じです。泼年の猛を积った GridData オブジェクトを栏喇するには 2 奶りの数恕があります。呵介の数恕は、このようにフィ〖ルドを木に肋年するものです。

GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.grabExcessHorizontalSpace = true;
button1.setLayoutData(gridData);

2 つ誊は守网な API、つまり GridData で年盗されているスタイルビットを网脱するものです。

button1.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));

悸狠、ある硷の办忍弄なスタイルの寥み圭わせは、蝗脱の狠に守网なように呵介から脱罢されています。

button1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

庙罢して瓦しいのは、FILL_ の烧いた守网なスタイルの寥み圭わせは alignment と grab の尉数を肋年するということです。GridData スタイルビットには靠刀猛か enum のフィ〖ルドだけが蝗われます。眶猛デ〖タのフィ〖ルドは木に肋年してください。

(Swing プログラマ〖は庙罢) GridData のフィ〖ルドの豺棱に掐る涟に、呵稿にひとつ承えておいてください。GridData オブジェクトを浩网脱しないでください。GridLayout で瓷妄している Composite 惧のウィジットは、链てユニ〖クな GridData オブジェクトを积たないといけません。ウィジットが芹弥される狠にそれらのレイアウトデ〖タが null の眷圭、ユニ〖クな GridData オブジェクトが栏喇されます。

HorizontalAlignment と VerticalAlignment

alignment フィ〖ルドを蝗って、ウィジットが呈灰グリッドの垮士か库木、あるいはその尉数のどちらに芹弥されるかを回年することができます。それぞれのフィ〖ルドは肌の猛のどれか办つを积つことができます。

  • BEGINNING (焊路え)
  • CENTER (面丙路え)
  • END (宝路え)
  • FILL (链挛を塔たす)

デフォルトの horizontalAlignment は BEGINNING (焊路え) です。verticalAlignment では CENTER になります。

3 误 5 つ Button の毋に提りましょう。Button 5 の horizontalAlignment を恃构してみます。

horizontalAlignment = GridData.BEGINNING (デフォルト) image047.jpg
horizontalAlignment = GridData.CENTER image049.jpg
horizontalAlignment = GridData.END image051.jpg
horizontalAlignment = GridData.FILL image053.jpg
HorizontalIndent

horizontalIndent フィ〖ルドを蝗って、ウィジットを回年したピクセル眶だけ宝にずらすことができます。このフィ〖ルドは舍奶、horizontalAlignment が BEGINNING の箕のみ罢蹋があります。スタイルビットではインデントを回年できませんので、肌の毋では Button 5 を 4 ピクセルインデントしています。

image055.jpg

GridData gridData = new GridData();
gridData.horizontalIndent = 4;
button5.setLayoutData(gridData);
HorizontalSpan と VerticalSpan

span フィ〖ルドを蝗って、ウィジットを办つ笆惧のグリッドセルを纲ぐように弥くことができます。これは FILL alignment と票箕に蝗われることが驴いようです。毋では Button 5 は肌のように呵稿の 2 セル粗を纲いでいます。

image057.jpg

GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.horizontalSpan = 2;
button5.setLayoutData(gridData);

もし Wide Button 2 の数を 2 セル粗に纲がせたいのなら、こう今くことになるでしょう。

image059.jpg

GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.horizontalSpan = 2;
button2.setLayoutData(gridData);

Button 3 を侥 2 セル粗に纲がせたいのなら、こうなります。

image061.jpg

GridData gridData = new GridData();
gridData.verticalAlignment = GridData.FILL;
gridData.verticalSpan = 2;
button3.setLayoutData(gridData);
GrabExcessHorizontalSpace と GrabExcessVerticalSpace

grabExcessHorizontalSpace と grabExcessVerticalSpace フィ〖ルドは、たいてい Text や List, Canvas といった络きめのウィジットに蝗われ、それらを呈羌している Composite を络きくしたときにこのウィジットも办斤に络きくなるようにします。Text を玻に途ったスペ〖スを玻艰りする(grabbing excess horizontal space)ように肋年すると、ユ〖ザ〖が Shell をリサイズした眷圭、Text は糠しく叫丸たスペ〖スを链て狸めるようになりますが、票じ乖の侍のウィジットは傅のサイズのままでいるでしょう。もちろん、途ったスペ〖スを玻艰りする ようなウィジットは Shell が井さくなったときに办戎呵介に井さくなるウィジットです。Button 3 が侥 2 セル粗に纲るような黎镍の毋をもう办刨艰り惧げましょう。

image062.jpg

ウィンドウをリサイズしても、帽にウィンドウが络きくなるだけです。

image064.jpg

さて、Button 3 を侥にも玻にも途ったスペ〖スを玻艰りするように肋年し、B1 と B4 を侥に弓がるように肋年します (スペ〖スの玻艰りはしない)。もう办刨ウィンドウをリサイズしてみましょう。

image066.jpg

海搀は Button 3 は侥と玻どちらにも弓がり、B4 は侥に弓がりました。戮のボタンは傅のサイズのままです。Button 3 が侥に途ったスペ〖スを玻艰りし、それが 2 つの乖を纲いでいるので、纲がれた呵稿の乖が侥に弓がったのです。侥に弓がるよう肋年されているにも簇わらず、B1 の络きさは恃わっていないことに庙誊してください。B1 のある乖は侥に弓がっていないからです。Button 3 は玻にもスペ〖スを玻艰りするようにもなっているので、その误が玻に弓がると、误を塔たすように络きくなります。これがその 5 つボタンのコ〖ドです。

Button button1 = new Button(shell, SWT.PUSH);
button1.setText("B1");
GridData gridData = new GridData();
gridData.verticalAlignment = GridData.FILL;
button1.setLayoutData(gridData);

new Button(shell, SWT.PUSH).setText("Wide Button 2");

Button button3 = new Button(shell, SWT.PUSH);
button3.setText("Button 3");
gridData = new GridData();
gridData.verticalAlignment = GridData.FILL;
gridData.verticalSpan = 2;
gridData.grabExcessVerticalSpace = true;
gridData.horizontalAlignment = GridData.FILL;
gridData.grabExcessHorizontalSpace = true;
button3.setLayoutData(gridData);

Button button4 = new Button(shell, SWT.PUSH);
button4.setText("B4");
gridData = new GridData();
gridData.verticalAlignment = GridData.FILL;
button4.setLayoutData(gridData);

new Button(shell, SWT.PUSH).setText("Button 5");

たいていのアプリケ〖ションウィンドウでは、办つ笆惧のウィジットを、スペ〖スを玻艰りするように肋年したくなることがよくあります。剩眶のウィジットが票じスペ〖スを玻艰りしようとすると、途ったスペ〖スはウィジット粗に堆霹に芹尸されます。

image068.jpg image070.jpg

スペ〖スの玻艰りについて呵稿にひとつ承えておいてください。Composite が玻に弓がって灰ウィジットが垮士にできた途尸なスペ〖スを玻艰りすると、そのウィジットのある误も链て络きくなります。Composite が侥に弓がって灰ウィジットが库木にできた途尸なスペ〖スを玻艰りすると、そのウィジットのある乖も链て络きくなります。このことが芭に绩しているのは、 逼读を减けた误や乖にあるウィジットが alignment を FILL に肋年されているのなら、そのウィジットも弓がるということです。BEGINNING や CENTER, END の alignment 肋年では弓がりません。つまり、误や乖が弓がっても、ウィジットは BEGINNING や CENTER, END の疤弥から瓢きません。

WidthHint と HeightHint

widthHint と heightHint フィ〖ルドを蝗って、ウィジットに艰らせたい升と光さをピクセル眶で回年することができます。しかし、これは GridLayout 惧の戮の动扩弄な肋年と顶圭しない眷圭に嘎ります。5 ボタン 3 误の毋に提って、Button 5 に升 70 ピクセル、光さ 40 ピクセルを肋年してみましょう。コ〖ドではこうなります。

GridData gridData = new GridData();
gridData.widthHint = 70;
gridData.heightHint = 40;
button5.setLayoutData(gridData);

傅のサイズの Button 5 は焊に、升 70 ピクセル、光さ 40 ピクセルの Button 5 は宝に绩します。

image071.jpg image073.jpg

しかし Button 5 の horizontalAlignment を FILL に肋年した眷圭、升 70 ピクセルという肋年は GridLayout では减け掐れられない、ということに庙罢してください。

升と光さ回绩を蝗うにあたって呵稿にひとつコメントしておきます。あるプラットフォ〖ムで斧ばえが紊かったとしても、侍のプラットフォ〖ムではそう でないかもしれません。プラットフォ〖ム粗でのフォントサイズやウィジットの极脸なサイズの般いを雇えると、ピクセルの猛をハ〖ドコ〖ディングするのはた いていの眷圭呵帘の数恕ではありません。ですから、升や光さの回绩を蝗うのであれば呵井嘎にとどめておいてください。

剩花な GridLayout の毋

海までの GridLayout の毋は、フィ〖ルドがどう怠墙するか绩すためのかなり帽姐なものでした。これからその链てを低め哈んだ、もうすこし哈み掐った毋を刁げましょう。缄今きの ラフスケッチから幌めて、どのようなウィンドウを栏喇するか、グリッドにいくつ误が涩妥か、セルを纲ぐウィジットはあるかどうかを疯めていきます。

image074.gif

それでは哭からコ〖ディングしましょう。布のようになります。プログラムをもっと烫球くするためにすこしロジック婶をつけ裁えてみました。毋えば Browse... ボタンを病すと FileDialog を倡いて Image ファイルを粕み哈み、Canvas のペイントリスナ〖で山绩します。Delete ボタンは Image を猴近します。Enter ボタンを病すと附哼山绩面の袱と霍い肩の攫鼠を叫蜗します。この毋は粕荚がレイアウトのコ〖ドに礁面してプログラムのスタイルに锨わされないように、帽办 の main メソッドで今かれています。

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;

public class ComplexGridLayoutExample {
  static Display display;
  static Shell shell;
  static Text dogName;
  static Combo dogBreed;
  static Canvas dogPhoto;
  static Image dogImage;
  static List categories;
  static Text ownerName;
  static Text ownerPhone;

  public static void main(String[] args) {
      display = new Display();
      shell = new Shell(display);
      shell.setText("Dog Show Entry");
      GridLayout gridLayout = new GridLayout();
      gridLayout.numColumns = 3;
      shell.setLayout(gridLayout);

      new Label(shell, SWT.NONE).setText("Dog's Name:");
      dogName = new Text(shell, SWT.SINGLE | SWT.BORDER);
      GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
      gridData.horizontalSpan = 2;
      dogName.setLayoutData(gridData);

      new Label(shell, SWT.NONE).setText("Breed:");
      dogBreed = new Combo(shell, SWT.NONE);
      dogBreed.setItems(new String [] {"Collie", "Pitbull", "Poodle", "Scottie"});
      dogBreed.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));

      Label label = new Label(shell, SWT.NONE);
      label.setText("Categories");
      label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));

      new Label(shell, SWT.NONE).setText("Photo:");
      dogPhoto = new Canvas(shell, SWT.BORDER);
      gridData = new GridData(GridData.FILL_BOTH);
      gridData.widthHint = 80;
      gridData.heightHint = 80;
      gridData.verticalSpan = 3;
      dogPhoto.setLayoutData(gridData);
      dogPhoto.addPaintListener(new PaintListener() {
         public void paintControl(final PaintEvent event) {
             if (dogImage != null) {
                event.gc.drawImage(dogImage, 0, 0);
             }
         }
      });

      categories = new List(shell, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
      categories.setItems(new String [] {
         "Best of Breed", "Prettiest Female", "Handsomest Male",
         "Best Dressed", "Fluffiest Ears", "Most Colors",
         "Best Performer", "Loudest Bark", "Best Behaved",
         "Prettiest Eyes", "Most Hair", "Longest Tail",
         "Cutest Trick"});
      gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
      gridData.verticalSpan = 4;
      int listHeight = categories.getItemHeight() * 12;
      Rectangle trim = categories.computeTrim(0, 0, 0, listHeight);
      gridData.heightHint = trim.height;
      categories.setLayoutData(gridData);

      Button browse = new Button(shell, SWT.PUSH);
      browse.setText("Browse...");
      gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
      gridData.horizontalIndent = 5;
      browse.setLayoutData(gridData);
      browse.addSelectionListener(new SelectionAdapter() {
         public void widgetSelected(SelectionEvent event) {
             String fileName = new FileDialog(shell).open();
             if (fileName != null) {
                dogImage = new Image(display, fileName);
             }
         }
      });

      Button delete = new Button(shell, SWT.PUSH);
      delete.setText("Delete");
      gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_BEGINNING);
      gridData.horizontalIndent = 5;
      delete.setLayoutData(gridData);
      delete.addSelectionListener(new SelectionAdapter() {
         public void widgetSelected(SelectionEvent event) {
             if (dogImage != null) {
                dogImage.dispose();
                dogImage = null;
                dogPhoto.redraw();
             }
         }
      });

      Group ownerInfo = new Group(shell, SWT.NONE);
      ownerInfo.setText("Owner Info");
      gridLayout = new GridLayout();
      gridLayout.numColumns = 2;
      ownerInfo.setLayout(gridLayout);
      gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
      gridData.horizontalSpan = 2;
      ownerInfo.setLayoutData(gridData);
      new Label(ownerInfo, SWT.NONE).setText("Name:");
      ownerName = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER);
      ownerName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

      new Label(ownerInfo, SWT.NONE).setText("Phone:");
      ownerPhone = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER);
      ownerPhone.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

      Button enter = new Button(shell, SWT.PUSH);
      enter.setText("Enter");
      gridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
      gridData.horizontalSpan = 3;
      enter.setLayoutData(gridData);
      enter.addSelectionListener(new SelectionAdapter() {
         public void widgetSelected(SelectionEvent event) {
             System.out.println("\nDog Name: " + dogName.getText());
             System.out.println("Dog Breed: " + dogBreed.getText());
             System.out.println("Owner Name: " + ownerName.getText());
             System.out.println("Owner Phone: " + ownerPhone.getText());
             System.out.println("Categories:");
             String cats[] = categories.getSelection();
             for (int i = 0; i < cats.length; i++) {
                System.out.println("\t" + cats[i]);
             }
         }
      });

      shell.pack();
      shell.open();
      while (!shell.isDisposed()) {
         if (!display.readAndDispatch()) display.sleep();
      }
      if (dogImage != null) {
         dogImage.dispose();
      }
  }
}

これが Mary Smith さんが霍い袱の Fifi をドッグショ〖にエントリ〖したときのウィンドウです。

image076.jpg

ウィンドウのサイズを络きくすると、このレイアウトはウィジットをこのように拇腊します。

image078.jpg

笆布のことに庙誊してください。

  • 呈灰グリッドは 7 乖 3 误あります。
  • Canvas である dogPhoto は弓く光くなっています。玻にも侥にも弓がるように肋年し、途尸なスペ〖スを玻艰りするように肋年してあるからです (ここでは山绩する Image のサイズは恃えていませんが、恃えることもできます)。
  • Combo である dogBreed は玻に弓くなっています。玻に弓がるように肋年してあり、Canvas と票じ误にあるからです。
  • Text である dogName は玻に弓くなっています。玻に弓がるように肋年してあり、纲いでいる误の办つの面に Canvas があるからです。
  • List である categories は侥に络きくなっています。侥に弓がるように肋年してあり、Canvas が纲いでいる乖をこのウィジットも纲いでいるからです。
  • List である categories が侥に络きくなったので、库木スクロ〖ルバ〖は久えています (これは络きくなったりはしません)。
  • Group である ownerInfo は弓くなっています。玻に弓がるように肋年してあり、またいでいる误の办つの面に Canvas があるからです。
  • この Group は Composite のサブクラスでもあるので、これ极咳 2 乖 2 误の GridLayout を积っています。
  • Text である ownerName と ownerPhone は玻に弓くなっています。Group である ownerInfo が弓くなると、その GridLayout 惧でこれらの Text が玻にも侥にも弓がるように肋年し、途尸なスペ〖スを玻艰りするように肋年してあるからです
  • Button である browse と delete は警しだけインデントされています。玻に弓がるように肋年してあり、票じ升を积っているからです。
  • delete は乖の面で惧に芹弥されるように肋年されています。
  • "Categories" とある Label は categories のリストの惧で面丙に芹弥されています。
  • Button である enter は纲いでいる 3 误の面で宝娄にくるように芹弥されています。
  • Canvas である dogPhoto は升と光さの回绩を涂えられています。山绩する Image を 80x80 ピクセルになるべくしたいからです。
  • List である categories は、そのフォントの 12 擒尸の升の回绩を涂えられています。介袋步箕に 12 改の灰妥燎を掐れておきたいからです。

FormLayout *New in 2.0*

FormLayout は FormAttachment をウィジットの娄烫に侯り、レイアウトデ〖タとして呈羌することで怠墙します。アタッチメント*3 とはウィジットの泼年の娄烫を、科 Composite の回年した疤弥に、あるいは票じレイアウト惧の侍のウィジットに儡缅させるものです。これを蝗うとウィジットのレイアウトに络きな嚼起拉をもたせることができます。

FormLayout 肋年材墙フィ〖ルド

MarginWidth, MarginHeight

FormLayout での margin フィ〖ルドは GridLayout での margin フィ〖ルドとほとんど票じです。焊宝のマ〖ジンは marginWidth で肋年し、惧布は marginHeight で肋年します。マ〖ジンはアタッチメントでウィジットごとに肋年することもできます。FormLayout でのデフォルトマ〖ジンは 0 です。

マ〖ジンを肋年するには、FormLayout を栏喇し margin フィ〖ルドに猛を肋年します。肌のコ〖ドでは科 Composite の 惧布焊宝 4 娄烫链てに 5 ピクセルのマ〖ジンを肋年しています。

Display display = new Display ();
Shell shell = new Shell (display);
FormLayout layout= new FormLayout ();
layout.marginHeight = 5;
layout.marginWidth = 5;
shell.setLayout (layout);

FormData オブジェクトのフィ〖ルド

FormData オブジェクトを蝗って、FormLayout 惧のウィジットをどのように芹弥するか肋年します。FormData オブジェクトでウィジットの 4 娄烫のアタッチメントを肋年します。このアタッチメントで娄烫それぞれの疤弥を回年するわけです。ウィジットに FormData オブジェクトをセットするには、setLayoutData メソッドを蝗ってください。このようにします。

Button button1 = new Button(shell, SWT.PUSH);
button1.setText("B1");
button1.setLayoutData(new FormData());

もっとも、このコ〖ドで栏喇した FormData オブジェクトにはアタッチメントがありません。そういう眷圭はデフォルトのアタッチメントが肋年されますが、それでは FormLayout を蝗う罢蹋も网守拉もありません。デフォルトのアタッチメントではウィジットは科 Composite の焊惧の眉に儡缅します。链てのウィジットにデフォルトのアタッチメントが肋年されていると、ウィジットは链て科 Composite の焊惧儿に弥かれ、ウィジットの惧にウィジットが姥み脚なるように芹弥されてしまいます。

Left, Right, Top そして Bottom

left, right, top, bottom フィ〖ルドには、ウィジット娄烫のそれぞれ焊、宝、惧、布に滦炳した FormAttachment オブジェクトを肋年できます。これらのフィ〖ルドは肌のように肋年します。

FormData formData = new FormData();
formData.top = new FormAttachment(0,60);
formData.bottom = new FormAttachment(100,-5);
formData.left = new FormAttachment(20,0);
formData.right = new FormAttachment(100,-3);
button1.setLayoutData(formData);

FormAttachment オブジェクトはウィジットの泼年の娄烫にアタッチメントを肋年します。娄烫が儡缅するところは驴くあります。科 Composite の泼年の疤弥あるいはその眉、戮のウィジットの钨り圭った娄烫あるいは瓤滦娄の娄烫、あるいはウィジットの面丙婶です。科 Composite の泼年の疤弥への儡缅とはウィジットの娄烫をそこに芹弥するものです。ですから儡缅するとウィジットの娄烫は、科 Composite のサイズのパ〖センテ〖ジで回年した疤弥へ撅に芹弥されるようになります。科 Composite の眉へ儡缅するときのパ〖センテ〖ジは 0% あるいは 100% になります。戮ウィジットの钨り圭った娄烫にアタッチメントを儡缅すると、ウィジットの回年した娄烫が戮ウィジットの办戎夺い娄烫に撅に钨り圭うようにな ります。戮ウィジットの瓤滦娄の娄烫へアタッチメントを儡缅すると、ウィジットの回年した娄烫が戮ウィジットの办戎斌い娄烫と撅に事ぶようになります。そ して、戮ウィジットの面丙婶にアタッチメントを儡缅すると、ウィジットは戮ウィジットの面丙に芹弥されるようになります。これらの肋年にはオフセットを回 年することもできます。

FormData オブジェクトになんのアタッチメントも肋年しない眷圭のデフォルトのふるまいは、このように科 Composite の焊惧儿にウィジットを儡缅させるものです。

image080.jpg

button1.setLayoutData(new FormData());

庙罢して瓦しいのは、アタッチメントをまったく肋年していないウィジットが办つ笆惧あると、それらはウィンドウ惧で票じデフォルトの疤弥を狸めることになり、ウィジットは侍のウィジットの惧に姥み脚なっていくということです。FormAttachment オブジェクトについては票叹のセクションで拒しく棱汤します。

Width と Height

FormData での width と height フィ〖ルドを蝗うと、ウィジットに涩妥な升と光さを回年することができます。回年した升と光さの猛がアタッチメントと顶圭する眷圭は痰浑されます。アタッ チメントをある镍刨肋年するとウィジットの升と光さは疯まるのですが、娄烫の链てにアタッチメントを肋年したくないと蛔うことがよくあるでしょう。そうい う眷圭は、肌のように*4升と光さを肋年すると守网です。

FormData formData = new FormData(20,30);
formData.top = new FormAttachment(0,60);
formData.left = new FormAttachment(20,0);
button1.setLayoutData(formData);

帽に升か光さを回年したいのなら、木儡 FormData オブジェクトの width か height フィ〖ルドにセットしてください。

FormData formData = new FormData ();
formData.width = 30;
formData.top = new FormAttachment(0,60);
formData.bottom = new FormAttachment(100,-5);
formData.left = new FormAttachment(20,0);
button1.setLayoutData(formData); 

Button を科 Composite の尉眉に儡缅している眷圭、科 Composite をリサイズするとその Button も办斤に凯び教みするということに庙罢してください。

FormAttachment オブジェクト

FormAttachment オブジェクトはウィジットの泼年の娄烫にアタッチメントを肋年します。ウィジットの 4 娄烫链てにアタッチメントを肋年する涩妥はありません。ほとんどの眷圭、1 つか、もう 1 つアタッチメントを肋年するだけで浇尸にウィジットの芹弥眷疥を回年できます。しかし、努磊な疤弥にウィジットを芹弥するために、警なくとも焊か宝の娄烫 のどちらか、惧か布の娄烫のどちらかにアタッチメントを肋年すべきです。ウィジットの焊娄烫だけにアタッチメントを肋年し、宝娄烫にはしなかった眷圭、 ウィジットはその焊娄烫を答洁に疤弥疯めされ、极脸なサイズをとります (サイズが妥滇されていて、アタッチメントと顶圭しない眷圭はそのサイズをとります)。焊娄烫にも宝娄烫にも肋年しなかった眷圭、デフォルトの疤弥はウィ ンドウの焊眉になります。笆惧のことは娄烫の惧布についても碰てはまります。

泼年の疤弥への儡缅

儡缅のタイプには驴くありますが、呵介に科 Composite の泼年の疤弥への儡缅から艰り惧げましょう。肌のように 100 までのパ〖センテ〖ジの猛で肋年します。

image082.jpg

FormData formData = new FormData();
formData.top = new FormAttachment(50,0);
button1.setLayoutData(formData);

このコ〖ドでは Button の惧娄烫を、科 Composite (ここでは Shell) の光さ 50% の疤弥にオフセット 0 で芹弥しています。Shell をリサイズしても、肌のように Button の惧娄烫は撅に光さ 50% のところにあります。

image084.jpg

オフセット猛を肋年した眷圭、Button の惧娄烫は科 Composite の光さ 50% のところから肋年した赖あるいは砷のピクセル眶だけ、ずらして芹弥されます。

肌のように、パ〖センテ〖ジを蝗わずに Button の疤弥を肋年することもできます。

FormData formData = new FormData();
formData.top = new FormAttachment(30,70,10);
button1.setLayoutData(formData);

これは、科 Composite の光さを 70 帽疤とし、惧から 30 帽疤のところに Button の惧娄烫を赖のオフセット 10 ピクセルで芹弥しています。

科 Composite への儡缅

肌は科 Composite の眉への儡缅です。肋年の慌数は泼年の疤弥への儡缅と票じですが、疤弥は 0% か 100% になります。0% の疤弥は库木では科 Composite 惧眉、垮士では焊眉となります。宝眉と布眉は 100% の疤弥になります。ですから、ウィジットを科 Composite の宝眉に儡缅させるのなら、帽に 100% の疤弥に肋年したアタッチメントを栏喇すればいいのです。

image086.jpg

FormData formData = new FormData();
formData.right = new FormAttachment(100,-5);
button1.setLayoutData(formData);

ここでは、Button の宝娄烫を科 Composite (ここでは Shell) の宝眉から 5 ピクセルのオフセットで芹弥しています。庙罢しておきますが、オフセットは办数羹にしか年盗できません。ウィジットのオフセットを布数羹か宝数羹に肋年し たいのなら、オフセットは赖の猛になります。惧数羹か焊数羹に肋年したいのなら、砷の猛になります。この毋では Shell がリサイズされても、Button は撅に宝眉から 5 ピクセルの疤弥にあります。

image088.jpg

戮ウィジットへの儡缅

3 つ誊は、票じ科 Composite 惧にある戮ウィジットの娄烫への儡缅です。ウィジットの娄烫を戮ウィジットの钨り圭った娄烫に儡缅したり (デフォルト)、瓤滦娄の娄烫に儡缅したりできます。また、ウィジットを戮ウィジットの面丙婶に芹弥することもできます。これらには链てオフセットを回年 できます。

呵も办忍弄な戮ウィジットへの儡缅の慌数は、钨り圭った娄烫に儡缅するものです。肌のコ〖ド毋を斧てください。

FormData formData = new FormData();
formData.top = new FormAttachment(20,0);
button1.setLayoutData(formData);

FormData formData2 = new FormData();
formData2.top = new FormAttachment(button1,10);
button2.setLayoutData(formData2);

ここでは button2 の惧娄烫と button 1 の布娄烫は儡缅しています。button1 の布娄烫と button2 の惧娄烫は钨り圭っているからです。

image090.jpg

庙誊してほしいのは、ウィンドウをリサイズすると、button1 の惧娄烫の疤弥は撅に Shell の光さ 20% のところにあるのでそれに圭わせて败瓢し、button2 も惧娄烫が button 1 の布娄烫 (钨り圭っている娄烫) から 10 ピクセル布にあるのでともに败瓢するということです。

image092.jpg

デフォルトではウィジットの钨り圭った娄烫に儡缅しますが、瓤滦娄の娄烫に儡缅させることもできます。これはウィジットを俐妨に事べるのに守网で す。肋年するには、アタッチメントを肌のように TOP, BOTTOM, LEFT, RIGHT アライメントを回年して栏喇します。

formData2.top = new FormAttachment(button1,0,SWT.TOP);

肌のコ〖ド毋では、button1 の惧娄烫は Shell の光さ 20% のところに芹弥されています。button2 の惧娄烫は、TOP アライメントを回年して button1 の惧娄烫と事ぶように芹弥されています。このことが罢蹋しているのは、button2 の惧娄烫もまた Shell の光さ 20% のところに芹弥されているということです。

FormData formData = new FormData(50,50);
formData.top = new FormAttachment(20,0);
button1.setLayoutData(formData);

FormData formData2 = new FormData();
FormData2.left = new FormAttachment(button1,5);
formData2.top = new FormAttachment(button1,0,SWT.TOP);
button2.setLayoutData(formData2);

このコ〖ドを悸乖すると肌のようになります。

Unders1.jpg

呵稿に艰り惧げる儡缅のタイプは、ウィジットを戮ウィジットの面丙婶に芹弥するものです。これはウィジット票晃のサイズが佰なっているときに守网です。肋年するには、アタッチメントを肌のように CENTER アライメントを回年して栏喇します。

formData.top = new FormAttachment(button1,0,SWT.CENTER);

ここでは、ウィジットの惧娄烫を、ウィジットが戮ウィジットの面丙に弥かれるような疤弥にオフセット 0 で芹弥しています。面丙アタッチメントは、それを肋年したのがウィジットの惧娄烫でも布娄烫でもその尉数でも票じ冯蔡になります。この眷圭、ウィジットは 惧娄烫が面丙に弥かれるわけではなく、ウィジット链挛が面丙に弥かれるからです。ですから回年は 1 つの娄烫に乖うだけで浇尸です。肌の毋を斧てください。

Unders2.jpg

FormData formData1 = new FormData (50,50);
button1.setLayoutData(formData1)

FormData formData2 = new FormData ();
formData2.left = new FormAttachment (button1,5);
formData2.top = new FormAttachment (button1,0,SWT.CENTER);
button2.setLayoutData (formData2);

屯」な数恕で FormAttachment を蝗えば、屯」なレイアウトを肋年することができます。FormLayout をレイアウトの肋年に守网なクラスにすることで、FillLayout や RowLayout, GridLayout では豺疯できないケ〖スを输うことができます。

脚妥: 桔茨するようなアタッチメントを年盗しないでください。毋えば、 button2 の焊娄烫を button1 の宝娄烫に儡缅しながら、票箕に button1 の宝娄烫を button2 の焊娄烫に儡缅したりしないでください。これはレイアウトを肋年し册ぎることとなり、踏年盗のふるまいを苞き弹こします。姜位するアルゴリズムを蝗っては いますが、冯蔡はどうなるか尸かりません。ですから、ウィジットを肋年し册ぎないように丹を烧けてください。ウィジットを努磊に芹弥するのに涩妥なだけの アタッチメントを蝗ってください。

FormLayout の毋

ここまでの FormLayout の链ての毋は、FormAttachment がどのように怠墙するか绩すためにウィンドウに 1 つか 2 つしか Button を弥いていません。ここでは驴眶のアタッチメントを蝗ってどのようにレイアウトをするか绩すために、もうすこし Button を蝗った词帽な毋を刁げましょう。

image098.jpg

FormData data1 = new FormData();
data1.left = new FormAttachment(0,5);
data1.right = new FormAttachment(25,0);
button1.setLayoutData(data1);

FormData data2 = new FormData();
data2.left = new FormAttachment(button1,5);
data2.right = new FormAttachment(100,-5);
button2.setLayoutData(data2);

FormData data3 = new FormData(60,60);
data3.top = new FormAttachment(button1,5);
data3.left = new FormAttachment(50,-30);
data3.right = new FormAttachment(50,30);
button3.setLayoutData(data3);

FormData data4 = new FormData();
data4.top = new FormAttachment(button3,5);
data4.bottom = new FormAttachment(100,-5);
data4.left = new FormAttachment(25,0);
button4.setLayoutData(data4);

FormData data5 = new FormData();
data5.bottom = new FormAttachment(100,-5);
data5.left = new FormAttachment(button4,5);
button5.setLayoutData(data5);

このコ〖ドでは、button1 も button2 も惧娄烫へのアタッチメントを肋年していません。button3 は焊娄烫と宝娄烫の尉数にパ〖センテ〖ジでの猛の回年とオフセットの回年をしているので、レイアウトの焊宝の面看の疤弥に弥かれます。button4 と button5 は レイアウト撵烫から 5 ピクセルのオフセットで儡缅されています。

image100.jpg

ウィンドウをリサイズすると、アタッチメントの赂哼がもっとはっきりします。button1 は焊娄烫と宝娄烫を儡缅しているので、リサイズにともなって络きくなります。ただしその宝娄烫が撅にウィンドウの升の 25% の疤弥にあることに庙誊してください。button2 も焊宝尉娄烫を儡缅しているので、票じように络きくなります。焊娄烫は button1 と儡缅しているので、撅にウィンドウの升の 25% からオフセット 5 ピクセルの疤弥にあります。button3 は焊宝の面看から瓢きません。button4 は惧娄烫と布娄烫を儡缅しているのでリサイズすると侥に凯びますが、焊娄烫だけ儡缅し宝娄烫はしていないので、玻に弓がることはありません。 button5 のサイズは恃わっていません。しかし、button5 は撅に button4 から焊に 5 ピクセル、ウィンドウ撵烫から 5 ピクセルの疤弥にあります。

image102.jpg

剩花な FormLayout の毋

もう警し哈み掐ったウィジットの芹弥に FormLayout をどう蝗うか棱汤しましょう。そのために GridLayout で蝗ったドッグショ〖の毋をもう办刨刁げます。票じようなレイアウトになりますが、まったく侍のコンセプトを蝗っています。

さて、GridLayout で闪いたラフスケッチを饯赖するところから幌めます。ウィジットをどこに芹弥するかだけではなく、どのように芹弥するかも闪いてみました。このコ〖ド毋では惧揭の儡缅のタイプ链てを蝗っています。

Unders3.jpg

import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;

public class ComplexFormLayoutExample {
   static Display display;
   static Shell shell;
   static Image dogImage;
   static Text dogNameText;
   static Combo dogBreedCombo;
   static Canvas dogPhoto;
   static List categories;
   static Text nameText;
   static Text phoneText;

   public static void main(String[] args){
       display = new Display();
       shell = new Shell(display);
       FormLayout layout= new FormLayout();
       layout.marginWidth = 5;
       layout.marginHeight = 5;
       shell.setLayout(layout);
       shell.setText("Dog Show Entry");

       Group ownerInfo = new Group(shell, SWT.NONE);
       ownerInfo.setText("Owner Info");
       FormLayout ownerLayout = new FormLayout();
       ownerLayout.marginWidth = 5;
       ownerLayout.marginHeight = 5;
       ownerInfo.setLayout(ownerLayout);

       Label dogName = new Label(shell, SWT.NONE);
       dogName.setText("Dog's Name:");
       dogNameText = new Text(shell, SWT.SINGLE | SWT.BORDER);
       Label dogBreed = new Label(shell, SWT.NONE);
       dogBreed.setText("Breed:");
       dogBreedCombo = new Combo(shell, SWT.NONE);
       dogBreedCombo.setItems(new String [] {"Collie", "Pitbull", "Poodle", "Scottie"});
       Label photo = new Label(shell, SWT.NONE);
       photo.setText("Photo:");
       dogPhoto = new Canvas(shell, SWT.BORDER);
       Button browse = new Button(shell, SWT.PUSH);
       browse.setText("Browse...");
       Button delete = new Button(shell, SWT.PUSH);
       delete.setText("Delete");
       Label cats = new Label (shell, SWT.NONE);
       cats.setText("Categories");
       categories = new List(shell, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
          categories.setItems(new String [] {
          "Best of Breed", "Prettiest Female", "Handsomest Male",
          "Best Dressed", "Fluffiest Ears", "Most Colors",
          "Best Performer", "Loudest Bark", "Best Behaved",
          "Prettiest Eyes", "Most Hair", "Longest Tail",
          "Cutest Trick"});
        Button enter = new Button(shell, SWT.PUSH);
       enter.setText("Enter");

       FormData data = new FormData();
       data.top = new FormAttachment (dogNameText,0,SWT.CENTER);
       dogName.setLayoutData(data);

       data = new FormData();
       data.left = new FormAttachment (dogName,5);
       data.right = new FormAttachment (100,0);
       dogNameText.setLayoutData(data);

       data = new FormData();
       data.top = new FormAttachment (dogBreedCombo,0,SWT.CENTER);
       dogBreed.setLayoutData(data);

       data = new FormData();
       data.top = new FormAttachment (dogNameText,5);
       data.left = new FormAttachment (dogNameText,0,SWT.LEFT);
       data.right = new FormAttachment (categories,-5);
       dogBreedCombo.setLayoutData(data);

       data = new FormData(80,80);
       data.top = new FormAttachment (dogBreedCombo,5);
       data.left = new FormAttachment (dogNameText,0,SWT.LEFT);
       data.right = new FormAttachment (categories,-5);
       data.bottom = new FormAttachment (ownerInfo,-5);
       dogPhoto.setLayoutData(data);
       dogPhoto.addPaintListener(new PaintListener() {
          public void paintControl(final PaintEvent event) {
              if (dogImage != null) {
                 event.gc.drawImage(dogImage, 0, 0);
              }
          }
          });

       data = new FormData();
       data.top = new FormAttachment (dogPhoto,0,SWT.TOP);
       photo.setLayoutData(data);
 
       data = new FormData();
       data.top = new FormAttachment (photo,5);
       data.right = new FormAttachment (dogPhoto, -5);
       browse.setLayoutData(data);
       browse.addSelectionListener(new SelectionAdapter() {
          public void widgetSelected(SelectionEvent event) {
              String fileName = new FileDialog(shell).open();
              if (fileName != null) {
                 dogImage = new Image(display, fileName);
              }
          }
          });

       data = new FormData();
       data.left = new FormAttachment (browse,0,SWT.LEFT);
       data.top = new FormAttachment (browse,5);
       data.right = new FormAttachment (dogPhoto, -5);
       delete.setLayoutData(data);
       delete.addSelectionListener(new SelectionAdapter() {
          public void widgetSelected(SelectionEvent event) {
              if (dogImage != null) {
                 dogImage.dispose();
                 dogImage = null;
                 dogPhoto.redraw();
              }
          }
          });

       data = new FormData(90,140);
       data.top = new FormAttachment (dogPhoto,0,SWT.TOP);
       data.right = new FormAttachment (100,0);
       data.bottom = new FormAttachment (enter,-5);
       categories.setLayoutData(data);

       data = new FormData();
       data.bottom = new FormAttachment (categories,-5);
       data.left = new FormAttachment (categories,0,SWT.CENTER);
       cats.setLayoutData(data);

       data = new FormData();
       data.right = new FormAttachment (100,0);
       data.bottom = new FormAttachment (100,0);
       enter.setLayoutData(data);
       enter.addSelectionListener(new SelectionAdapter() {
          public void widgetSelected(SelectionEvent event) {
              System.out.println("\nDog Name: " + dogNameText.getText());
              System.out.println("Dog Breed: " + dogBreedCombo.getText());
              System.out.println("Owner Name: " + nameText.getText());
              System.out.println("Owner Phone: " + phoneText.getText());
              System.out.println("Categories:");
              String cats[] = categories.getSelection();
              for (int i = 0; i < cats.length; i++) {
                 System.out.println("\t" + cats[i]);
              }
          }
       });

       data = new FormData();
       data.bottom = new FormAttachment (enter,-5);
       data.left = new FormAttachment (0,0);
       data.right = new FormAttachment (categories,-5);
       ownerInfo.setLayoutData(data);

       Label name = new Label(ownerInfo, SWT.NULL);
       name.setText("Name:");
       Label phone = new Label(ownerInfo, SWT.PUSH);
       phone.setText("Phone:");
       nameText = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER);
       phoneText = new Text(ownerInfo, SWT.SINGLE | SWT.BORDER);

       data = new FormData();
       data.top = new FormAttachment (nameText,0,SWT.CENTER);
       name.setLayoutData(data);

       data = new FormData();
       data.top = new FormAttachment (phoneText,0,SWT.CENTER);
       phone.setLayoutData(data);

       data = new FormData();
       data.left = new FormAttachment (phone,5);
       data.right = new FormAttachment (100,0);
       nameText.setLayoutData(data);

       data = new FormData();
       data.left = new FormAttachment (nameText,0,SWT.LEFT);
       data.right = new FormAttachment (100,0);
       data.top = new FormAttachment (55,0);
       phoneText.setLayoutData(data);

       shell.pack();
       shell.open();

       while (!shell.isDisposed()) {
          if (!display.readAndDispatch())
              display.sleep();
       }
       display.dispose();
   }
}

これが、Mary Smith さんが霍い袱の Fifi をドッグショ〖にエントリ〖したときのウィンドウです。

Unders4.jpg

ウィンドウをリサイズすると、ウィジットは GridLayout でサイズが恃わったのと票屯にリサイズされます。

Unders5.jpg

迫极レイアウトクラスの侯り数

极 尸で迫极のレイアウトクラスを侯りたくなることがあるかもしれません。おそらく、そのようなレイアウトが妥滇するものはとても剩花なものでしょう。票じよ うな嘲囱をしているところがあるので、贷赂のコ〖ドを浩网脱したくなるかもしれません。あるいは、この尸填の梦急を栏かして?润撅に跟唯弄なレイアウトクラスを侯り惧げたくなるかもしれません。どちらにせよ、糠しいクラスを侯る涟には雇胃すべきことがあります。

  • そのレイアウトは GridLayout か FormLayout あるいはその寥圭せで菇喇できないでしょうか々
  • 袋略している冯蔡はリサイズリスナ〖を蝗ってもっと词帽に评られないでしょうか々
  • あなたは绕脱のレイアウトクラスを年盗したいのでしょうか々それとも帽にウィジットの疤弥を疯めたいだけなのでしょうか々

Composite のような呈羌ウィジットで蝗われている润撅に办忍弄なタイプのレイアウトを侯りたいのでなければ、帽にリサイズリスナ〖の面で灰ウィジットのサイズを纷换 して疤弥を疯めたほうが、ほとんどの眷圭词帽かつ紊いコ〖ドになります。SWT カスタムウィジットの驴くがその数恕で今かれています。呈羌ウィジットは Composite と Layout の尉数を蝗って悸刘することもできますが、Composite として悸刘し、その面のリサイズリスナ〖で灰ウィジットのレイアウトを、computeSize メソッドの面で极咳の庭黎サイズを纷换させたほうが汤澄で、途尸なクラスを崔みません。

まず、レイアウトがどのように怠墙するか斧ていきましょう。それから糠しいレイアウトクラスを侯ります。迫极レイアウトの毋は∪Creating Your Own Widgets Using SWT∩の Compound Widget Example セクションにもあり、そこではリサイズリスナ〖とレイアウトクラスでどうやって票じ嘲囱を捏丁するか捌柒しています。

レイアウトはどのように怠墙するか

Layout は链てのレイアウトクラスの藐据ス〖パ〖クラスです。メソッドは 2 つ、computeSize と layout しかありません。このクラスは肌のように年盗されています。

public abstract class Layout {
   protected abstract Point computeSize(
       Composite composite, int widthHint, int heightHint, boolean flushCache);
   protected abstract void layout(Composite composite, boolean flushCache);
}

computeSize メソッドは苞眶 composite の灰ウィジット链てを崔むような煌逞妨の升と光さを纷换します。これは、その灰ウィジット链ての疤弥とサイズがこの Layout クラスに今かれているアルゴリズムによって疯年された箕に乖われます。苞眶 widthHint と heightHint は煌逞妨の升と光さを动扩します。毋えば、その办数を动扩すると、レイアウトの络きさはもう办つの数羹にしか恃步しません。ここに SWT.DEFAULT を回年するとレイアウトは庭黎されるサイズをとります。

layout メソッドは苞眶 composite の灰ウィジットの疤弥とサイズを疯年します。Layout クラスではレイアウトに簇息した攫鼠、毋えば灰ウィジットの络きさ霹をキャッシュすることができます。苞眶 flushCache はキャッシュを粕み木すかどうか回年します。

Layout は Composite 面の灰ウィジットの疤弥とサイズを瓷妄するので、Composite クラスには Layout から钙び叫されるメソッドが年盗されています。

肌の 2 メソッドを蝗うと Composite から Layout オブジェクトを肋年、艰评できます。

public void setLayout(Layout layout);
public Layout getLayout();

アプリケ〖ションから科 Composite の layout メソッドを钙ぶことで、动扩弄に灰ウィジットを浩芹弥することもできます。

public void layout(boolean changed);
public void layout();
    // calls layout(true);

おそらく、これらのメソッドが蝗われるのは、灰ウィジットの肋年を恃えるとそのサイズと疤弥が恃步するような眷圭、毋えば灰ウィジットのフォントを 恃えたり、灰ウィジットのテキストや茶咙を恃えたり、灰ウィジットに糠しいウィジットを纳裁するような眷圭でしょう (灰ウィジットが恃步を帝箭する眷圭は layout メソッドを钙ぶ涩妥はありません。毋えばスクロ〖ルバ〖の烧いた剩眶乖 Text ウィジットでフォントやテキストを恃える眷圭です)。これらの恃步は极瓢弄に栏じ、弹こるべきイベントを苞き弹こしません。したがって科 Composite は恃步が尸からないので、layout メソッドを蝗って奶梦しなくてはいけません。しかし、このような数克をとるとウィンドウのチラツキを娃えることができます。なぜなら灰ウィジットが浩闪茶 されるのは、アプリケ〖ションが部刨も恃步してから科 Composite にレイアウトを妥懒したときだけであり、恃步ごとではないからです。Shell のウィンドウを倡いた*5稿 に灰ウィジットに惧揭のような恃步が弹き、layout メソッドを钙ばずにいると、おそらく灰ウィジットは、ウィンドウのリサイズなどが乖われるまでは赖しく芹弥されていないでしょう。shell.open () メソッドを钙び叫すとレイアウトも乖うということは承えておいてください。

computeSize メソッドは Composite 极咳の极脸なサイズを纷换します。これは Layout で疯年したクライアントエリア (clientArea) にトリム (trim) を裁えたものです。

public Point computeSize(int widthHint, int heightHint, boolean changed);
public Point computeSize(int widthHint, int heightHint);
    // calls computeSize(widthHint, heightHint, true);

クライアントエリアとは灰ウィジット链てを崔むような煌逞妨のことです。この面のウィジットは Layout によって芹弥されます。

public Rectangle getClientArea ();

トリムとはクライアントエリアの嘲娄にある挝拌のことです。トリムのサイズが 0 の Composite 巧栏クラスもあります。トリムはクライアントエリアの络きさを computeTrim メソッドに畔すことで纷换できます。

public Rectangle computeTrim (int x, int y, int width, int height);

pack メソッドを钙び叫すと、Composite は庭黎されるサイズをとります。

  public void pack(boolean changed);
      // calls setSize(computeSize(SWT.DEFAULT, SWT.DEFAULT, changed));
  public void pack();
      // calls pack(true);

layout メソッド、computeSize メソッド、pack メソッドにある boolean 苞眶は恃步フラグです。これが true ということは Composite の柒推がその极脸なサイズに逼读するように恃步していることを山しており、Layout が瘦积しているキャッシュは粕み木されます。Composite はリサイズされると layout(false) メソッドを钙び、その Layout を蝗って灰ウィジットをレイアウトをします。この眷圭、キャッシュは粕み木されません。このようにすることで、Layout は涩妥なときにだけ光コストの纷换をするようにしています。

キャッシュを蝗えばパフォ〖マンスは羹惧しますが、トリッキ〖なふるまいをすることも澄かです。そこで、链くキャッシュを蝗わないという联买をする こともできます。悸狠、コ〖ドが奥年するまではキャッシュを蝗わずに貉ませるのが办戎なのです。部をキャッシュすべきか雇えるときは、ウィジットの觉轮、 毋えば Label のテキストや List の灰妥燎の眶などをキャッシュしないように庙罢してください。

カスタムレイアウトの毋

アプリケ〖ションに库木の数羹拉を积ったウィジットがいくつかある眷圭、ColumnLayout を侯ってみるのもいいでしょう。ここでは灰ウィジットを帽办の误に芹弥するようなレイアウトクラスのシンプルなものを棱汤します。このクラスではマ〖ジン とスペ〖シングは盖年されています。灰ウィジットは链て票じ升になりますが、光さは极脸なサイズになります (SWT バ〖ジョン 2.0 からは RowLayout は橙磨され、type に SWT.VERTICAL を回年するとこの ColumnLayout と票じ慷る神いをするようになります。ですから、この毋は帽なる毋の办つで、悸狠に帽办の误にウィジットを芹弥する眷圭は、RowLayout を蝗ったほうがいいでしょう)。

ColumnLayout のコ〖ドは布のようになります。庙誊してほしいのは、呵も升弓い灰ウィジットの升と灰ウィジットの光さの下 (それにスペ〖シングを裁えたもの) をキャッシュし、それらの猛を computeSize メソッドでサイズを纷换するときと layout メソッドで灰ウィジットを芹弥するときに蝗っているということです。それらの猛は flushCache フラグが true のとき浩纷换されます。

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;

public class ColumnLayout extends Layout {
   // fixed margin and spacing
   public static final int MARGIN = 4;
   public static final int SPACING = 2;
  
   // cache
   Point [] sizes;
   int maxWidth, totalHeight;

protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
   Control children[] = composite.getChildren();
   if (flushCache || sizes == null || sizes.length != children.length) {
       initialize(children);
   }
   int width = wHint, height = hHint;
   if (wHint == SWT.DEFAULT) width = maxWidth;
   if (hHint == SWT.DEFAULT) height = totalHeight;
   return new Point(width + 2 * MARGIN, height + 2 * MARGIN);
}

protected void layout(Composite composite, boolean flushCache) {
   Control children[] = composite.getChildren();
   if (flushCache || sizes == null || sizes.length != children.length) {
       initialize(children);
   }
   Rectangle rect = composite.getClientArea();
   int x = MARGIN, y = MARGIN;
   int width = Math.max(rect.width - 2 * MARGIN, maxWidth);
   for (int i = 0; i < children.length; i++) {
       int height = sizes[i].y;
       children[i].setBounds(x, y, width, height);
       y += height + SPACING;
   }
}

void initialize(Control children[]) {
   maxWidth = 0;
   totalHeight = 0;
   sizes = new Point [children.length];
   for (int i = 0; i < children.length; i++) {
       sizes[i] = children[i].computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
       maxWidth = Math.max(maxWidth, sizes[i].x);
       totalHeight += sizes[i].y;
   }
   totalHeight += (children.length - 1) * SPACING;
}
}

肌のシンプルなコ〖ドで ColumnLayout を蝗ってみましょう。Button である grow と shrink は layout() メソッドを钙び、灰ウィジットの升を恃えてから、それらを动扩弄に浩芹弥しています。layout() メソッドを钙ぶのは layout(true) メソッドを钙ぶのと票じことで、灰ウィジットに簇息したキャッシュを粕み木すように ColumnLayout を肋年しています。Shell は髓レイアウト稿に pack() メソッドも钙ぶようにしています。こうすればウィンドウが髓搀糠しいサイズをとるようになります。

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

public class ColumnLayoutTest {
   static Shell shell;
   static Button button3;

   public static void main(String[] args) {
       Display display = new Display();
       shell = new Shell(display);
       shell.setLayout(new ColumnLayout());
       new Button(shell, SWT.PUSH).setText("B1");
       new Button(shell, SWT.PUSH).setText("Very Wide Button 2");
       (button3 = new Button(shell, SWT.PUSH)).setText("Button 3");
       Button grow = new Button(shell, SWT.PUSH);
       grow.setText("Grow Button 3");
       grow.addSelectionListener(new SelectionAdapter() {
          public void widgetSelected(SelectionEvent e) {
              button3.setText("Extreemely Wide Button 3");
              shell.layout();
              shell.pack();
          }
       });
       Button shrink = new Button(shell, SWT.PUSH);
       shrink.setText("Shrink Button 3");
       shrink.addSelectionListener(new SelectionAdapter() {
          public void widgetSelected(SelectionEvent e) {
              button3.setText("Button 3");
              shell.layout();
              shell.pack();
          }
       });
       shell.pack();
       shell.open();
       while (!shell.isDisposed()) {
          if (!display.readAndDispatch()) display.sleep();
       }
   }
}

このコ〖ドを悸乖すると焊の茶咙のようなウィンドウが附れます。Grow Button 3 ボタンを病すと、宝の茶咙のようになります。ウィンドウをマウスでリサイズするとボタンの升を弓く (豆くも) できますが、ボタンを侥に凯ばすことはできません。

image110.jpg image112.jpg

Compsite をオ〖バ〖ライドする

极尸で迫极のウィジットを侯る(∪Creating Your Own Widgets Using SWT∩に车维があります) 狠に Composite を费镜した眷圭、コ〖ドの悸刘には雇胃すべき爬が警しだけあります。

  • その Composite でトリミングがしたいのなら、computeTrim メソッドと getClientArea メソッドをオ〖バ〖ライドするのを撕れないでください。
  • layout() メソッドではなく layout(boolean) メソッドをオ〖バ〖ライドしてください。

迫极の Composite にある泼魔をもった嘲囱を涂えたいが、アプリケ〖ションからはレイアウトの回年をさせたくない眷圭があるかもしれません。それには、リサイズリスナ〖でレ イアウトの借妄をしてもいいですしプライベ〖トな迫极レイアウトを蝗ってもできます。どちらにせよ、肌のようにしておいたほうがいいでしょう。

  • setLayout メソッドが部もしないようにオ〖バ〖ライドしてください。
  • layout(boolean) メソッドがそのレイアウトのコ〖ドを钙ぶようにオ〖バ〖ライドしてください。
  • computeSize メソッドが赖しくウィジットのサイズを纷换できるようにオ〖バ〖ライドしてください。

まとめ

SWT はウィジットのレイアウトに屯」な数恕を捏丁しています。办戎シンプルで呵もよく蝗われるのは、筛洁のレイアウトクラスである FillLayout や RowLayout, GridLayout, FormLayout です。

极尸で迫极のレイアウトクラスを侯りたくなることがあるかもしれません。それが、泼魔ある嘲囱を捏丁するためだとしても、击たようなレイアウトの コ〖ドを浩网脱するためだとしても、ほとんどの眷圭は科 Composite 面のリサイズリスナ〖を蝗えば浇尸に脱が颅りるはずです。

SWT レイアウトクラスを妄豺するのにもうすこし缄锦けが瓦しいのであれば、SWT Example の org.eclipse.swt.examples.layoutexample を斧て布さい。

构糠泣箕:Tue Mar 30 00:00:00 JST 2004
キ〖ワ〖ド:
徊救:

*1 (条庙) ウィジットを呈羌するようなウィジット

*2 (条庙) アプリケ〖ションウィンドウを山附するクラス

*3 (条庙) Attachment: 儡缅湿

*4 (条庙) コンストラクタで升と光さを回年しています。FormData(int width, int height)

*5 (条庙) shell.open() を钙び叫した