概要

JSplitPaneのサイズが変更されてもその分割割合を維持するよう設定します。

サンプルコード

class SplitPaneWrapper extends JPanel {
  private final JSplitPane splitPane;

  protected SplitPaneWrapper(JSplitPane splitPane) {
    super(new BorderLayout());
    this.splitPane = splitPane;
    add(splitPane);
  }

  private static int getOrientedSize(JSplitPane sp) {
    return sp.getOrientation() == JSplitPane.VERTICAL_SPLIT
        ? sp.getHeight() - sp.getDividerSize()
        : sp.getWidth() - sp.getDividerSize();
  }

  @Override public void doLayout() {
    int size = getOrientedSize(splitPane);
    int loc = splitPane.getDividerLocation();
    BigDecimal ratio = BigDecimal.valueOf(loc / (double) size)
        .setScale(2, RoundingMode.HALF_UP);
    super.doLayout();
    if (splitPane.isShowing()) {
      EventQueue.invokeLater(() -> {
        int sz = getOrientedSize(splitPane);
        int iv = (int) (.5 + sz * ratio.doubleValue());
        splitPane.setDividerLocation(iv);
      });
    }
  }
}
View in GitHub: Java, Kotlin

解説

  • Default(ResizeWeight:0.5)
    • デフォルトのJSplitPaneJSplitPane#setResizeWeight(.5)を設定し、余分なスペースの配分方法を左右均等に設定
    • JSplitPaneのリサイズを繰り返していると余りや誤差?が常に左側のコンポーネントに積み重なるので、子コンポーネントの推奨サイズに基づいた分割割合から大きくズレてしまう場合がある
  • SplitPaneWrapper(Keep ratio)
    • JSplitPaneJPanelでラップし、そのJPanel#doLayout()をオーバーライドしてJSplitPaneの分割割合を補正
      • BasicSplitPaneUI.BasicHorizontalLayoutManager#distributeSpace(int space, boolean keepHidden)はオーバーライドしづらいのでJSplitPaneのDividerの位置を最大化後に変更すると同様にJPanelをラップして対応
      • super.doLayout()で再レイアウトする前のJSplitPane分割割合を保存
      • super.doLayout()実行後にJSplitPaneの新規サイズと保存していた分割割合からディバイダーの位置を計算
      • JSplitPane#setDividerLocation(...)を実行してリサイズ前の分割割合を復元
    • この方法でも誤差は発生するので完全に分割割合を維持することはできない

参考リンク

コメント