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); } } }