TITLE:JButtonなどの高さを変更せずに幅を指定
#navi(../)
#tags(JButton, JComboBox, JTextField, LayoutManager, SpringLayout)
RIGHT:Posted by &author(aterai); at 2004-11-29
*JButtonなどの高さを変更せずに幅を指定 [#d4f459ec]
高さはデフォルトのまま幅だけを指定して、``JButton``、``JComboBox``、``JTextField``などのサイズを変更します。

-&jnlp;
-&jar;
-&zip;

//#screenshot
#ref(http://lh5.ggpht.com/_9Z4BYR88imo/TQTIYyyZqRI/AAAAAAAAASs/SZslQQaTuFc/s800/ButtonWidth.png)

**サンプルコード [#xbca7694]
#code(link){{
Dimension dim = button1.getPreferredSize();
button1.setPreferredSize(new Dimension(100, dim.height));
button2.setPreferredSize(new Dimension(100, dim.height));
Box box1 = Box.createHorizontalBox();
box1.add(Box.createHorizontalGlue());
box1.add(button1);
box1.add(Box.createHorizontalStrut(5));
box1.add(button2);
box1.add(Box.createHorizontalStrut(5));
box1.add(Box.createRigidArea(new Dimension(0, dim.height+10)));
}}

**解説 [#v8878c59]
サンプルの下段のように``JButton``の幅を一定にそろえて水平に並べたい場合や、``GridBugLayout``でウエイトを指定するのが面倒といった場合に使用します。

上記のサンプルでは、まず``JButton``の``UI``がフォントサイズや文字列の長さから決めたデフォルトサイズを``getPreferredSize()``で取得しています。高さはそのまま利用し、幅だけ一定の値を設定して、新たなデフォルトサイズを作成し、``setPreferredSize()``しています。これで次から``getPreferredSize()``で帰ってくる値は、どちらのボタンでも全く同じになります。

この``getPreferredSize()``で得られる値を使用するかどうかは、レイアウトマネージャーによって異なりますが、水平方向にコンポーネントを並べる``BoxLayout``の場合は以下のようになるため、パネルをリサイズしても、ボタンのサイズはどちらも同じで変化しません。

- 幅: 推奨サイズ(``getPreferredSize``メソッド)から取得した値
- 高さ: 各コンポーネントの推奨サイズ(``getPreferredSize``メソッド)で得られた中からもっとも大きな値
-- 上記のサンプルで``button1.setPreferredSize(new Dimension(100, 0));``としても結果は同じ

例えば各ボタンを格納した親フレームを``pack()``する前に``JButton#getPreferredSize()``ではなく、``JButton#getSize()``でサイズを取得すると、``[width=0,height=0]``が帰ってきます。コンポーネントが表示されている場合、``getSize()``で得られるサイズは、その実際に表示されているサイズ(レイアウトマネージャーが決める)になります。

以下は``JLabel``を``getPreferredSize()``した場合の例です。初期状態(``preferredSize``が``null``)の場合は、``JLabel``の``UI``がサイズを計算しています。

#code{{
JLabel l = new JLabel();
l.setText("a"); //preferredSizeがnullの場合、UIがサイズを計算
//l.getPreferredSize() -> Dimension[width=6,height=13]

l.setText("aaaa"); //JLabelの場合、Fontサイズと文字列の長さなどで決まる
//l.getPreferredSize() -> Dimension[width=24,height=13]

l.setText("<html>aa<br>aa");
//l.getPreferredSize() -> Dimension[width=12,height=26]

l.setPreferredSize(new Dimension(10,10)); //preferredSizeを設定した場合
//l.getPreferredSize() -> Dimension[width=10,height=10]

l.setPreferredSize(null); //preferredSizeをnullに戻した場合
//l.getPreferredSize() -> Dimension[width=12,height=26]
}}

----
``JComboBox``、``JTextField``などのコンポーネントでは、[[JComboBoxなどの幅をカラム数で指定>Swing/SetColumns]]のように、カラム数で幅を指定することもできます。``JDK 1.5.0``でこの方法をしようすると、コンポーネントによって高さや余白などが微妙に異なりますが、``JDK 1.6.0``以上ならうまくサイズを指定することができます。

----
``setPreferredSize()``などを使わず、``LayoutManager``で``JButton``の幅を固定したい場合は、例えば``SpringLayout``を以下のように使用する方法などがあります。

#code{{
private static JComponent createRightAlignButtonBox2(
    List<JButton>list, int buttonWidth, int buttonHeight, int gap) {
  SpringLayout layout = new SpringLayout();
  JPanel p = new JPanel(layout);
  SpringLayout.Constraints pCons = layout.getConstraints(p);
  pCons.setConstraint(SpringLayout.SOUTH, Spring.constant(buttonHeight+gap+gap));

  Spring x     = layout.getConstraint(SpringLayout.WIDTH, p);
  Spring y     = Spring.constant(gap);
  Spring g     = Spring.minus(Spring.constant(gap));
  Spring width = Spring.constant(buttonWidth);
  for(JButton b: list) {
      SpringLayout.Constraints constraints = layout.getConstraints(b);
      constraints.setConstraint(SpringLayout.EAST, x = Spring.sum(x, g));
      constraints.setY(y);
      constraints.setWidth(width);
      p.add(b);
      x = Spring.sum(x, Spring.minus(width));
  }
  return p;
}
}}

**参考リンク [#gf6df44a]
- [[JComboBoxなどの幅をカラム数で指定>Swing/SetColumns]]
- [[SpringLayoutの使用>Swing/SpringLayout]]
- [http://www.jroller.com/santhosh/entry/how_do_you_layout_command Santhosh Kumar's Weblog]
-- 専用のレイアウトマネージャを作成するサンプルがあります。

**コメント [#c408da48]
- ``SpringLayout``などを使って幅を固定する方法を追加(更新日時は忘れました)。スクリーンショットは未更新。 -- [[aterai]] &new{2013-04-14 (日) 00:36:03};

#comment