技術的雑談-SwingのJLabel類の大きさの最適化
環境
JDK1.5.0_04とかそれ以上
目的
- JLabelの大きさを中の文字列の大きさや、フォントサイズによって切れないようにしたい。
- 多言語化対応などでラベル、ボタン、チェックボックスなどの表記が変わる恐れがある。
対処方法
文字列がきっちり収まる大きさを求める方法
例えば、JLable、JCheckBox,JRadioBox,JButtonはsetText(),setFont()した後に、getPreferredSize()を呼びます。
このメソッドの戻り値はこのコンポーネントを現在の表示設定で全体を表示する為の適切な大きさを示すDimensionオブジェクトです。
これをそのまま自分自身のsetSize()に突っ込んでやれば「自分が求める大きさ」に自動設定できることになります。
例) somethingSwingComponent.setSize(somethingSwingComponent.getPreferredSize());
但し、実際の表示サイズはそのコンポーネントが乗っているコンテナのLayoutによって制約を受けるので、絶対にそのラベルが求める大きさで表示されることを保障するにはLayoutManagerをnullで登録するか、最小サイズ(setMaximumSize())に突っ込んでやるぐらいしか考え付きません。
文字列の変化にラベルを自動的に追従させる
SwingのコンポーネントではaddPropertyChangeListener()メソッドを使って、PropertyChangeListenerをセットすることができます。
PropertyChangeListenerインターフェースは
public void propertyChange(PropertyChangeEvent evt) {}
というメソッドを持ち、コンポーネントの特定のプロパティーが変更された時にそれを通知してくれます。
引数のPropertyChangeEventオブジェクトにはgetPropertyName()というメソッドがあり、例えばJLabelでsetText("hogehoge")とすると、addPropertyChangeListener()で登録したPropertyChangeListenerのpropertyChange()メソッドが呼び出されます。
引数のPropertyChangeEventのgetPropertyName()によってどのプロパティーが変更されたのか知ることができるので、それによって適切な処理を書けばOKです。
例) 自分のTextが変更された時に自動的に自分の大きさを変える為のPropertyChangeListener /** * */ package test; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.JComponent; /** * @author sakamoto * */ public class TestPropertyChangeListener implements PropertyChangeListener { /** * */ public TestPropertyChangeListener() { super(); } /* (非 Javadoc) * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent evt) { // 変更前後のプロパティーの値もわかります System.out.println("***** " + evt.toString()); System.out.println("getNewValue() = " + evt.getNewValue()); System.out.println("getOldValue() = " + evt.getOldValue()); System.out.println("getPropertyName() = " + evt.getPropertyName()); // 変更されたプロパティー名で処理を分岐 if ("text".equals(evt.getPropertyName())) { // テキストが変更された時→自分の希望サイズを変更する処理 JComponent me = (JComponent)evt.getSource(); // Textが変更されたコンポーネントの取得 System.out.println("##### TEXT #####"); System.out.println("getPrefferedSize() = " + me.getPreferredSize()); // 適切な大きさの取得 me.setSize(me.getPreferredSize()); System.out.println("Parent PreferredSize = " + me.getParent().getPreferredSize()); } } }
これを使うには、大きさを自動追従させたいコンポーネントに対して、
someComponent.addPropertyChangeListener(new TestPropertyChangeListener());
を実行しておけばOK。
あとはずーっと、(removePropertyChangeListener()するまで)勝手にTextを換えるたびに適当な大きさになります。
レイアウト上の自動追従
上記の方法で勝手にコンポーネントの大きさが変わると当然全体のレイアウトが崩れますよね?
それを防ぐには…Layoutを使用して自動的に計算させればいいのですが、Layoutを使用していないときや、周りのコンポーネントの位置関係を計算させるのはどうすれば良いでしょう?
オブジェクト指向プログラムをしているのならそのコンポーネントの機能はそのコンポーネントを監視して実装したいですよね。
SwingのコンポーネントにはaddComponentListener()というメソッドがあり、これに好みのComponentListenerオブジェクトを渡すことによってコンポーネントの大きさなどが変わった際に自動的にそれを知りたい誰かに通知することが可能です。
ComponentListenerインタフェースには
- componentHidden(ComponentEvent e)
- コンポーネントが何かに隠れた時に呼び出される
- componentMoved(ComponentEvent e)
- コンポーネントがコンテナ上で移動されたら呼び出される
- componentResized(ComponentEvent e)
- コンポーネントのサイズが変更されたら呼び出される
- componentShown(ComponentEvent e)
- 隠されていたコンポーネントが表に表れたら呼び出される
のメソッドがあり、処理が必要なものをオーバーライドします。
ここではcomponentResized()をオーバーライドし、周りのコンポーネントの大きさを変更するコードを記述すればOKです。
但し、お互いにお互いのサイズをcomponentResized()の中で変更するようなコードを書くと「イベントの循環」になってしまうので注意してください。
履歴
2005/02/21 -- 初版
技術的雑談へ戻る