- PR -

複数JSplitPaneのディバイダの連動(同期)

1
投稿者投稿内容
未記入
会議室デビュー日: 2007/01/26
投稿数: 18
投稿日時: 2007-05-08 16:11
複数のJSplitPaneのディバイダを連動させたいと思っているのですが、いまいちうまくいかないのでもし実現された方がおられれば教えてください。イメージとしては、ディバイダを動かすと、他のディバイダもその移動ピクセル(?)分を調整したいと考えています。

以下がサンプルコードです。

<CODE>
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Vector;
import javax.swing.JComponent;
import javax.swing.JSplitPane;


public class DividerSynchronizer extends AbstractSynchronizer
implements PropertyChangeListener
{
private Vector components;


public DividerSynchronizer()
{
components = new Vector();
}

public void addComponent(JSplitPane split)
{
cache.add(split);
}

public void propertyChange(PropertyChangeEvent evt)
{
// Property change.
if(evt.getPropertyName() == JSplitPane.DIVIDER_LOCATION_PROPERTY)
{
int newDividerLocation = ((Integer)evt.getNewValue()).intValue();

for(int i=0; i<cache.size(); i++)
{
JSplitPane split = (JSplitPane)cache.get(i);
JSplitPane source = (JSplitPane)evt.getSource();

if( !split.equals(source) )
{
split.setDividerLocation(newDividerLocation);
}
}
}
}
}
</CODE>

このリスナークラスを連動させたい各JSplitPaneに追加してるのですが、setDividerLocationで再びPropertyChangeEventが発火されてループに入ってしまいます。またJSplitPaneによっては、移動距離に重みのようなものをつけて、移動距離を変動させたいのですが、どういったやり方が一番良いのでしょうか?

よろしくお願いします。

朝日奈ありす
大ベテラン
会議室デビュー日: 2007/05/02
投稿数: 189
お住まい・勤務地: 最北の地
投稿日時: 2007-05-08 17:07
無限ループになっているのであれば、動作を制御するフラグをもたせる方法がある。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-05-08 18:06
if(evt.getPropertyName() == JSplitPane.DIVIDER_LOCATION_PROPERTY)
でStringを==比較しているのが気になるなぁ。

私のほうでも試しに作って見ました。
下のJSplitPaneのディバイダを動かすと上のJSplitPaneのディバイダも連動して動きます。
方法論は簡単で、setDividerLocation()をオーバーライドしただけ。
コード:
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;

public class JSplitTest {
    /**
     * @param args
     */
    public static void main(String[] args) {
        final JSplitPane pane1 = new JSplitPane();
        JSplitPane pane2 = new JSplitPane(){
            /**
             * {@inheritDoc}
             * @see javax.swing.JSplitPane#setDividerLocation(double)
             */
            @Override
            public void setDividerLocation(double proportionalLocation) {
                super.setDividerLocation(proportionalLocation);
                pane1.setDividerLocation(proportionalLocation);
            }

            /**
             * {@inheritDoc}
             * @see javax.swing.JSplitPane#setDividerLocation(int)
             */
            @Override
            public void setDividerLocation(int location) {
                super.setDividerLocation(location);
                pane1.setDividerLocation(location);
            }
        };

        final JFrame frame = new JFrame();
        frame.setSize(320,320);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
        frame.getContentPane().add(pane1);
        frame.getContentPane().add(pane2);

        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                frame.setVisible(true);
            }
        });
    }
}

未記入
会議室デビュー日: 2007/01/26
投稿数: 18
投稿日時: 2007-05-09 03:39
>杏さん
ありがとうございます。一度試してみます。

>nagiseさん
なるほど、片方のJSplitPaneを継承させるわけですね。この場合、単方向の連動のみだと思うのですが、双方向の連動をさせたい場合は、継承でなくて、お互いを持たせてやればよいのでしょうか?

すみません、なぜかStringでなくてプリミティブタイプが返ってくると勘違いしていました。修正します。ありがとうございます。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-05-09 11:26
引用:

未記入さんの書き込み (2007-05-09 03:39) より:
なるほど、片方のJSplitPaneを継承させるわけですね。この場合、単方向の連動のみだと思うのですが、双方向の連動をさせたい場合は、継承でなくて、お互いを持たせてやればよいのでしょうか?



連動できるよ、というだけのサンプルなので簡易に書いていますが、
しっかりとした双方向連動させたいのであれば、
無名クラスではなく、まじめにクラスにしたほうがいいでしょうね。

イメージとしてはコンストラクタやsetterで連動する相手を渡してやるようにし、
クラス内のインスタンスフィールドにターゲットとなるJSplitPaneを保持し、
そのインスタンスに対してsetDividerLocation()してやればよいでしょう。

ただし、双方のsetDividerLocation()がオーバーライドされている場合、
互いに呼び合うことで、やはり無限ループに陥るので、
本来のsetDividerLocation()はオーバーライドしつつも、
super.setDividerLocation()を呼ぶための別メソッドを
用意しておくなどの工夫が必要です。

概要としては以下のような感じでしょうか。
※動作確認などはしていません
コード:
public class JSplitTest extends JSplitPane {
  /** 連動対象 */
  private JSplitPane target;

  public void setTarget(JSplitPane target) {
    this.target = target;
  }

  @Override
  public void setDividerLocation(double proportionalLocation) {
    super.setDividerLocation(proportionalLocation);
    if (this.target instanceof JSplitTest) {
      // 無限ループにならないように別メソッドを呼び出す
      this.target.setDividerLocationEx(proportionalLocation);
    } else {
      this.target.setDividerLocation(proportionalLocation);
    }
  }
  /** superの実装を呼ぶだけのメソッド */
  public void setDividerLocationEx(double proportionalLocation) {
    super.setDividerLocation(proportionalLocation);
  }

  // もう片方のオーバーロードも同様に処理する
}

1

スキルアップ/キャリアアップ(JOB@IT)