• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JSplitPaneのディバイダを展開、収納する
#navi(../)
RIGHT:Posted by [[terai]] at 2010-07-05
*JSplitPaneのディバイダを展開、収納する [#u9e01565]
JSplitPaneのディバイダをマウスのクリックなどで一気に展開、収納できるように設定します。
---
category: swing
folder: OneTouchExpandable
title: JSplitPaneのディバイダを展開、収納する
tags: [JSplitPane, Divider, ActionMap, ServiceManager, BasicService]
author: aterai
pubdate: 2010-07-05T01:22:49+09:00
description: JSplitPaneのディバイダをマウスのクリックなどで一気に展開、収納できるように設定します。
image: https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTQl4nQ4PI/AAAAAAAAAf0/y7DMbOexVWs/s800/OneTouchExpandable.png
---
* 概要 [#summary]
`JSplitPane`のディバイダをマウスのクリックなどで一気に展開、収納できるように設定します。

-&jnlp;
-&jar;
-&zip;
#download(https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTQl4nQ4PI/AAAAAAAAAf0/y7DMbOexVWs/s800/OneTouchExpandable.png)

#screenshot

**サンプルコード [#f93229db]
#code{{
* サンプルコード [#sourcecode]
#code(link){{
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, s1, s2);
splitPane.setOneTouchExpandable(true);
}}

**解説 [#b1964ebf]
上記のサンプルでは、JSplitPane#setOneTouchExpandable(true)と設定することで、ディバイダにJButtonが表示され、これらをクリックすることでディバイダを展開、収納することができるようになっています。
* 解説 [#explanation]
上記のサンプルでは、`JSplitPane#setOneTouchExpandable(true)`を設定するとディバイダに`JButton`が`2`つ表示され、これらをマウスでクリックすると`JSplitPane`の展開、収納ができます。

----
初期状態でディバイダを収納状態にする場合、Java 1.5以降では、splitPane.setDividerLocation(0);などとするだけではダメ((JSplitPane自体をリサイズすると、収納されているコンポーネントの最小サイズ(setMinimumSize)まで勝手に展開され))で、以下のような設定をする必要があります。
-Web Startで起動しなかった場合
--[[Bug ID: 5006095 Need a way to programmatically stick JSplitPane divider under j2sdk 1.5>http://bugs.sun.com/view_bug.do?bug_id=5006095]]
#code{{
try {
  Method setKeepHidden = BasicSplitPaneUI.class.getDeclaredMethod(
      "setKeepHidden", new Class[] { boolean.class });
  setKeepHidden.setAccessible(true);
  setKeepHidden.invoke(splitPane.getUI(), new Object[] { new Boolean(true) });
}catch(Exception e) {
  e.printStackTrace();
}
}}
- `Java 1.5`以降で`JSplitPane#setDividerLocation(0);`などとしてディバイダを収納状態にした場合、`JSplitPane`自体をリサイズすると収納されているコンポーネントの最小サイズ(`setMinimumSize`)まで展開される
- 収納状態を維持したい場合、リフレクションを使って`BasicSplitPaneUI#setKeepHidden(true)`メソッドを実行したり`Divider`に表示されている`JButton`を取得実行する方法がある
-- [https://bugs.openjdk.org/browse/JDK-5006095 Bug ID: 5006095 Need a way to programmatically stick JSplitPane divider under j2sdk 1.5]
-- [[JSplitPaneの収納状態を維持する>Swing/KeepHiddenDivider]]
- KBD{HOME}キーやKBD{END}キー(KBD{F8}キーなどで`Divider`にフォーカスを移動した状態で)を押して展開、収納する方法では`Divider`中の`JButton`を押して展開、収納した場合と動作が異なる
-- KBD{HOME}キー、KBD{END}キーで展開、収納
--- 前回の状態に一旦戻らずに展開、収納される
--- `JSplitPane`自体をリサイズすると収納されているコンポーネントの最小サイズ(`setMinimumSize`)まで自動的に展開される
--- `JSplitPane#getActionMap()#get("selectMin")`などで取得できる`Action`では`setKeepHidden(boolean)`が使われていない
- `GTKLookAndFeel`はワンタッチボタンをサポートしないので`SplitPane.supportsOneTouchButtons: Boolean.FALSE`が設定されている

-Web Startで起動した場合
--dividerから直接JButton(名前がついていない……)を取得し実行
#code{{
EventQueue.invokeLater(new Runnable() {
  @Override public void run() {
    Container divider = ((BasicSplitPaneUI)splitPane.getUI()).getDivider();
    for(Component c: divider.getComponents()) {
      if(c instanceof JButton) {
        ((JButton)c).doClick();
        break;
      }
    }
  }
});
}}
* 参考リンク [#reference]
- [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/JSplitPane.html#setOneTouchExpandable-boolean- JSplitPane#setOneTouchExpandable(boolean) (Java Platform SE 8)]
- [https://bugs.openjdk.org/browse/JDK-5006095 Bug ID: 5006095 Need a way to programmatically stick JSplitPane divider under j2sdk 1.5]
- [[JSplitPaneの収納状態を維持する>Swing/KeepHiddenDivider]]
- [https://stackoverflow.com/questions/37233738/jsplitpane-setonetouchexpandabletrue-is-not-shown java - JSplitPane setOneTouchExpandable(true) is not shown - Stack Overflow]

----
HOMEキーやENDキー(F8キーなどでdividerにフォーカスを移動した状態で)を押して展開、収納する方法では、divider中のJButtonを押して展開、収納した場合と動作が異なります。
-HOMEキー、ENDキーで展開、収納
--前回の状態に一旦戻らずに展開、収納される
--JSplitPane自体をリサイズすると、収納されているコンポーネントの最小サイズ(setMinimumSize)まで勝手に展開される
---JSplitPane#getActionMap()#get("selectMin")などで取得できるActionでは、setKeepHidden(boolean)が使われていない
* コメント [#comment]
#comment
- ソースファイルをダウンロードして`eclipse`でプロジェクト作成しそこにコピーしたのですが、「インポートされた `javax.jnlp` は見つかりません」と出てきて実行出来ないのですが、 `javax.jnlp`はどこに置けば良いのでしょうか? -- &user(ニートン); &new{2012-02-21 (火) 08:06:33};
-- `eclipse`はほとんど使ったことがないのでインポートの詳細(もしかして`Ant`の`build.xml`を取り込む機能がある?)が分からないのですが、`javax.jnlp`パッケージは、`${java.home}/lib/javaws.jar`にあるので、ここにクラスパスが通っていないのかもしれません。このサンプルでは、`javax.jnlp.*`は使用しないので、`build.xml`から`<pathelement location="${java.home}/lib/javaws.jar" />`を削除するか、または、`eclipse`で新規プロジェクトを作成し、ソースコードだけ貼り付けるのが簡単だと思います。 -- &user(aterai); &new{2012-02-21 (火) 17:15:21};
- 「`eclipse`で新規プロジェクトを作成し、ソースコードだけ貼り付けるのが簡単だと思います。」の通りしていたのですが。。。結果的には`jnlp.jar`ファイルを`jdk1.6`の中から探して`eclipse`の「外部`jar`を追加」で動作いたしました。お騒がせしました。それと、この`javax.jnlp`は`BasicService`関連のクラスファイルが入ってるようなので削除できないみたいです。-- &user(ニートン); &new{2012-02-22 (水) 18:41:04};
-- すいません。「このサンプルでは、`javax.jnlp.*`は使用しないので...」はデタラメで、`BasicService`が取得できるかどうかで、`Web Start`で起動したのかどうかを判断する部分を見落としていました。`Web Start`で起動した場合は、`getComponents()`でボタンを検索する方法で、ローカルから起動した場合は、リフレクションで`private`な`setKeepHidden`メソッドを取得して実行する方法を使っています。大変失礼しましたm(__)m。 -- &user(aterai); &new{2012-02-22 (水) 18:59:52};

**参考リンク [#leece45e]
-[[Bug ID: 5006095 Need a way to programmatically stick JSplitPane divider under j2sdk 1.5>http://bugs.sun.com/view_bug.do?bug_id=5006095]]

**コメント [#m26676c6]
#comment