JSplitPaneは、2つのコンポーネントを保持し、間の仕切りをユーザーが変更してペインの大きさを変えられるもの。
(ユーザーが大きさを変えられるというところがJPanel(GridLayout)等と異なる)
|
|
/**
* スプリットペインの初期化
*/
private void initPane(Container c) {
//エディター,テーブル,ツリーやスクロール等の他のコンポーネント
Component p1 = 〜;
Component p2 = 〜;
JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT); //上下分割
split.add(p1);
split.add(p2);
split.setDividerSize(4);
c.add(split);
}
JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, p1, p2);
| 値 | 内容 |
|---|---|
| HORIZONTAL_SPLIT | 左右分割(横分割)。縦線で仕切られ、左右に動かせる。 |
| VERTICAL_SPLIT | 上下分割(縦分割)。横線(水平線)で仕切られ、上下に動かせる。 |
コンポーネントを2つ指定する必要があるが、同一のコンポーネント(インスタンス)を指定することは出来ない。
(1つのJEditorPaneを別々のJScrollPaneに入れて登録してもダメ)
間の仕切り線のことは『ディバイダー』と呼ぶ。
JSplitPaneに登録したコンポーネントによっては、ユーザーがディバイダーを動かせないこともある。
(JEditorPaneを2つだとダメで、JScrollPaneでラップしたJEditorPaneが2つならOK)
たぶん初期サイズによるのだと思うが、確認していない…いずれにしても、JScrollPaneと併せて使うのが良さそう。
| メソッド | 説明 | 備考 |
|---|---|---|
| getDividerSize() | ディバイダーのサイズ(太さ)を返す。 | Look&Feelによって、デフォルトの幅は異なる。 (JDK1.6で試したら、)標準だと10、Windows外観だと5。 たぶん4くらいが一番無難。 |
| setDividerSize(サイズ) | ディバイダーのサイズを変更する。 | |
| getDividerLocation() | ディバイダーの位置を返す。 | |
| setDividerLocation(位置) | ディバイダーの位置を設定する。 | |
| setDividerLocation(割合) | ディバイダーの位置を0〜1.0の割合で指定する。 | |
| getMinimumDividerLocation() | ディバイダーの有効な最小位置。[2009-10-25] | |
| getMaximumDividerLocation() | ディバイダーの有効な最大位置。[2009-10-25] |
左右分割の場合、デフォルトでは「左領域が推奨サイズ」で表示されるが、「右領域が最小サイズ」で表示したいことがある。[2009-10-25]
(別の表現をすれば、「左領域が最大サイズ」で表示したい)
(上下分割なら、デフォルトは「上領域が推奨サイズ」だが、「上領域が最大サイズ」「下領域が最小サイズ」で表示したい)
単純に考えると、getMaximumDividerLocation()で一番右の仕切り位置を取得し、それを新しい位置としてセットし直せばいい。
が、getMaximumDividerLocation()は一度表示されてから(厳密には各コンポーネントのサイズが計算されてから)でないと正しい値を返さない。
なので、例えばJFrameであればsetVisible(true)を呼び出して表示するのだから、それをオーバーライドすればいい。
さらに(これはJDK1.6.0_13のJSplitPaneの内部処理クラスであるBasicSplitPaneUIのバグだと思うのだが)、
マウスでドラッグしないと正しい値が返ってこない。
または、デフォルトのディバイダーサイズを変更している場合でないと(マウスでドラッグするまで)正しい値が返ってこない。
public int getMaximumDividerLocation(JSplitPane jc) {
Dimension splitPaneSize = splitPane.getSize();
int maxLoc = 0;
Component rightC = splitPane.getRightComponent();
〜
maxLoc -= dividerSize;
〜
return Math.max(getMinimumDividerLocation(splitPane), maxLoc);
}
要するに各コンポーネントのサイズ(splitPaneというフィールドを使っていて、引数のjcは使われてないし(苦笑))を取得して最大位置を計算しているのだが、その中でdividerSizeというフィールドを使っている。
これはディバイダーの幅を自前で保持しているフィールドらしいのだが、デフォルト状態では0のまま(爆)
つまりディバイダーの幅の分だけ間違った値が返ってくる。
JSplitPane#setDividerSize()で以前と異なる値をセットする(同じ値だとBasicSplitPaneUI内の変更は行われない)か、マウスでドラッグすると
BasicSplitPaneUI#dividerSizeが正しい値になるので、JSplitPane#getMaximumDividerLocation()も正しい結果を返すようになる。
以上のことを勘案し、JFrameでJSplitPaneの第1領域(左・上)を最大にするには、以下のようにすればよい。
@SuppressWarnings("serial")
public class MaxSplitFrame extends JFrame {
protected JSplitPane split;
private boolean firstVisible;
〜
protected void initPane(Container container) {
Component comp1 = 〜;
Component comp2 = 〜;
split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
split.add(comp1);
split.add(comp2);
{ //BasicSplitPaneUIのバグ対応(ディバイダーサイズを変更する)
int ds = split.getDividerSize();
split.setDividerSize(ds + 1);
split.setDividerSize(ds);
}
container.add(split);
firstVisible = true;
}
@Override
public void setVisible(boolean b) {
super.setVisible(b);
if (b && firstVisible) {
//初めて表示するときだけ、ディバイダーの初期位置を最大位置にする
firstVisible = false;
int loc = split.getMaximumDividerLocation();
split.setDividerLocation(loc);
}
}
}