homeup mail to
sub title

GridBagの使い方1
( 19990131 )

Japanese/English

たまには実用的な情報を載せなきゃってことで、突然JavaのGridBagLayout入門!なぜGridBagLayoutなのかというと、Javaを使い込んでいる人ならよ〜くわかると思うけど、Javaを使ってウィンドウを作り、文字入力やボタンなどの部品をきれいに配置しようとしても、なかなか思うように配置できない。

Javaはご存知のように基本ソフト(OS)に左右されないプログラミングを目指しているので、Windowsでしかまともに表示できないっていうのはまずいわけ。

で、BorderLayout、GridLayout、FlowLayoutなどなど、部品の配置を調整する「レイアウトマネージャー」ってものがいくつか用意されてる。ところがそれぞれクセがあって、なかなか思うような配置にならない。

たとえばBorderLayoutは、東・西・南・北・真ん中という、とってもアバウトな指定しかできない。GridLayoutは、大きさが同じ部品ならタテ・ヨコにきれいにならぶけど、大きさがバラバラな部品まで無理やり同じ大きさにされちゃうのでカッコ悪いったらありゃしない。などなど。

そこでJavaを愛用するプログラマーの一人が、開発元のサン・マイクロシステムズに「これを使ってくれぃ!」って提供したのがGridBagLayout。このおかげでJavaでもかなりきれいに部品を配置できるようになった。

ところがこのGridBagLayout、「頭のいい」プログラマーが作っただけあってむちゃくちゃ使いにくい。

じっさいサン・マイクロシステムズのJavaプログラマー向け質問集には、こんなQ&Aが載ってるくらい。「GridBagLayout はどうしてこんなに使うのが難しいのですか?」詳しくはここをクリックしてそのQ&Aの本文を読んでみて

サン・マイクロシステムズのJavaホームページには、ちゃんと使い方の説明が載ってるんだけど(ここをクリック)、長ったらしい英文だから英語の分からない人は読む気がしない。それに、どう使ったら良いのかという視点からの説明がない。

でも、いちど分かっちゃえば、このGridBagLayoutはかなり強力なので、Javaプログラマーの皆さんはぜひこのページを参考にして、思いどおりの部品配置を楽しんでほしい。

じゃあまずGridBagLayoutを使う前に、どういう準備が必要か?そこから始めよう。方眼紙を用意して、必要な部品を下図のようにスケッチしてみて。

業務用ソフトにはありがちな配置。左半分はJListコンポーネント。右半分にはJLabelとJTextFieldをいくつか。そして右下にボタンJButtonが2つ。

しかもこうやってできた結果は下図のようにひどいありさま。

部品のすき間がぜ〜んぶギチギチになっちゃう。これじゃあひどすぎる。JBuilderのような有料の開発ツールを使わずに、見栄えのいい画面を作ろうと思えばGridBagLayoutを使うしかないわけ。

ではGridBagLayoutを使う前の下準備の話のつづき。部品の配置をよく見て、画面全体をタテ・ヨコに区切ってみよう。下図を参考にしてね。

この図をみると、ヨコは5等分、タテはまぁ6等分くらいでいいか、という見当がつく。右下のボタンだけがうまくおさまらないけど、もうちょっと右につめて右端の2マス分に収めるようにしよう。X軸方向は5マス、Y軸方向は6マス。これを覚えておいて。

で、それぞれの部品がX軸の何マス目、Y軸の何マス目にあるか、メモっていく。注意してほしいのは、X軸・Y軸とも1マス目じゃなくて、0マス目から始まるってこと。

JList はX軸0マス目、Y軸0マス目(つまりいちばん左上のすみっこ)。ヨコは2マス分占領して、タテは6マス分占領してる。

JLabelはすべてX軸の2マス目に、タテにずらりとならんでいる。

JTextFieldはすべてX軸の3マス目に、タテにずらりとならんでいて、横幅は2マス分占領している。

JButtonはX軸2マス目、Y軸3マス目からにしておこう。ちょっとこの図ではズレてるけど。

さぁ、ここまで決まればあとはコーディングだけ。まず部品を全部作ろう。

list1だけは中身がないとつぶれちゃうので、大きさを強制的に指定するよ(現実にはリスト項目を追加するからこの必要はないだろうけど)。他の部品はGridBagLayoutマネージャがlist1の大きさを基準にして勝手に計算してくれる。便利だねぇ。

次にいよいよGridBagLayoutの登場!

getContentPane()を使ってるのは、たまたまテストに使ったプログラムではJFrameを使ってたから。swingコンポーネントをJFrameに追加するときは、必ずgetContentPane()を使ってRootPaneを取得するのが「お作法」だから(このあたりは市販のswing入門書を読んで)。もしJFrameのかわりにJPanelを使うのなら、getContentPane()を使わずに直接setLayout(gb)できる。

ここまでは、他のレイアウトマネージャを使うのとまったく同じ。仮にBorderLayoutなら、

だから。さて、GridBagLayoutはここからが違う。もうひとつGridBagConstraintsが必要。英語でconstraintsとは「束縛」とか「制約条件」という意味。GridBagLayoutを使うときは、GridBagConstraintsを同時に使って、部品一つひとつを表示するときの「制約条件」を付けていく。まずGridBagConstraintsを作ろう。

そして最初の部品、list1の「制約条件」を定義する。ここでさっきメモったことを思い出そう。list1は「X軸0マス目、Y軸0マス目(つまりいちばん左上のすみっこ)。ヨコは2マス分占領して、タテは6マス分占領してる」んだった。これがlist1の「制約条件」になる。

まず「X軸の0マス目だから、Y軸0マス目」だから、

このようにGridBagConstraintsには、gridxgridyというプロパティがある。そこにX軸の位置と、Y軸の位置を代入すればOK。次に「ヨコは2マス分占領して、タテは6マス分占領してる」。これは、

こんどは同じGridBagConstraintsの、gridwidthgridheightに、それぞれX軸方向の幅(width)と、Y軸方向の高さ(height)を代入する。これで「制約条件」がすべてととのった。そこでここまで代入した「制約条件」をGridBagLayoutに教えてやる。

教えてあげたら最後に、JFrameそのものにlist1を追加しよう。

残りの部品も同じようにして「制約条件」を付けてどんどん追加するだけ。たとえば次のlabel1の場合は次のようになる。

X軸の2マス目、Y軸の0マス目で、X軸方向に1マス占領、Y軸方向に1マス占領。この制約条件をまずGridBagLayoutに教えてから、JFrame本体に追加。残りの部品もこの調子で追加すると...

X軸、Y軸の位置だけじゃなくて、X軸方向(gridwidth)・Y軸方向(gridheight)に何マス分の大きさを占領してるか、それもちゃんと制約条件として教えてやらないとダメ。

このプログラムを見れば分かるように、GridBagConstraintsは何度も使いまわしができる。一つのGridBagConstraints(このプログラムではcという名前の変数)の、gridx、gridy、gridwidht、gridheightを何度も代入しなおしてリサイクルしてるのが分かるね。

ではこのプログラムでウィンドウを実際に表示させてみよう。すると、

BorderLayoutやGridLayoutを使ったバージョンよりはましだけど、まだちょっとカッコ悪い。「氏名」「郵便番号」とか右ぞろえになってないし、文字入力欄は左ぞろえになってない。2つのボタンの間も不自然にすき間があいてる。まだまだ美しくない!次はGridBagConstraintsの便利な機能をつかってもっと美しい画面を作ってみよう。

というわけで次へ進むには、ここをクリック!

GridBagLayoutができる前は、これだけの配置を作るのにも一苦労だった。たとえば...まずGridLayout(GridBagLayoutとまぎらわしいから気をつけてね)でウィンドウを左右2列に割って、その右側をBorderLayoutにして、そのCENTERの部分をさらにGridLayoutで左右2列に割って、JLabelとJTextFieldを配置し、ボタン部分はBorderLayoutのSOUTHを使って...とレイアウトマネージャをいくつも「入れ子」にしないとできなかった。

    JList  list1  = new JList();
JLabel label1 = new JLabel("氏名");
JLabel label2 = new JLabel("郵便番号");
JLabel label3 = new JLabel("住所");
JLabel label4 = new JLabel("電話番号");
JTextField text1 = new JTextField(10);
JTextField text2 = new JTextField(5);
JTextField text3 = new JTextField(20);
JTextField text4 = new JTextField(10);
JButton button1 = new JButton("登録");
JButton button2 = new JButton("終了");
list1.setPreferredSize(new Dimension(160, 160));

    GridBagLayout gb = new GridBagLayout();
getContentPane().setLayout(gb);

    BorderLayout bl = new BorderLayout();
getContentPane().setLayout(bl);

    GridBagConstraints c = new GridBagConstraints();

    c.gridx = 0;
c.gridy = 0;

    c.gridwidth  = 2;
c.gridheight = 6;

    gb.setConstraints(list1, c);

    getContentPane().add(list1);

    c.gridx = 2;
c.gridy = 0;
c.gridwidth  = 1;
c.gridheight = 1;
gb.setConstraints(label1, c);
getContentPane().add(label1);

    c.gridx = 2;
c.gridy = 1;
c.gridwidth  = 1;
c.gridheight = 1;
gb.setConstraints(label2, c);
getContentPane().add(label2);
c.gridx = 2;
c.gridy = 2;
c.gridwidth  = 1;
c.gridheight = 1;
gb.setConstraints(label3, c);
getContentPane().add(label3);
c.gridx = 2;
c.gridy = 3;
c.gridwidth  = 1;
c.gridheight = 1;
gb.setConstraints(label4, c);
getContentPane().add(label4);
c.gridx = 3;
c.gridy = 0;
c.gridwidth = 2;
c.gridheight = 1;
gb.setConstraints(text1, c);
getContentPane().add(text1);
c.gridx = 3;
c.gridy = 1;
c.gridwidth = 2;
c.gridheight = 1;
gb.setConstraints(text2, c);
getContentPane().add(text2);
c.gridx = 3;
c.gridy = 2;
c.gridwidth = 2;
c.gridheight = 1;
gb.setConstraints(text3, c);
getContentPane().add(text3);
c.gridx = 3;
c.gridy = 3;
c.gridwidth = 2;
c.gridheight = 1;
gb.setConstraints(text4, c);
getContentPane().add(text4);
c.gridx = 3;
c.gridy = 5;
c.gridwidth = 1;
c.gridheight = 1;
gb.setConstraints(button1, c);
getContentPane().add(button1);
c.gridx = 4;
c.gridy = 5;
c.gridwidth = 1;
c.gridheight = 1;
gb.setConstraints(button2, c);
getContentPane().add(button2);


無断転載禁止

サラリーマンを考える 日本的なるものを考える 日常生活を考える
「おじさん」を考える 映画/音楽/書物を考える 情報システムを考える
愛と苦悩の日記 筆者のYouTubeチャンネル

homeup mail to