1

JSliders を「リンク」して合計値に上限を設ける最良の方法は何ですか?

ユーザーがスピード、敏捷性、持久力、正確さなどのキャラクター特性を指定できる格闘ゲームを想像してみてください。ユーザーには 100 ポイントが与えられ、どのように選択しても割り当てられますが、すべてのスライダーの合計値が 100 を超えてはなりません。つまり、スライダーはそのような増加を許可してはなりません。

ユーザーが速度、敏捷性、持久力にそれぞれ 30 ポイントを割り当てた場合、精度のスライダーは最大 10 ポイントを許可する必要があります (30 + 30 + 30 + 10 = 100 のため)。ただし、各スライダーの範囲は変更しないでください (この場合は 0 ~ 100)。

これが理にかなっていることを願っています。助けてくれてありがとう。

4

2 に答える 2

5

"nichts einfacher als das" - dachte ... (insert name :-)

基本的に、そのような拡張機能はすべてモデルに実装する必要があります。JSlider の場合、それは BoundedRangeModel です。「結合された」最大値を尊重するために、その値を実装/拡張および強制します。何かのようなもの

public static class LimitedBoundedRangeModel extends DefaultBoundedRangeModel {

    BoundedRangeModel limit;

    public LimitedBoundedRangeModel(BoundedRangeModel limit) {
        this.limit = limit;
    }

    /** 
     * @inherited <p>
     */
    @Override
    public void setRangeProperties(int newValue, int newExtent, int newMin,
            int newMax, boolean adjusting) {
        if (limit != null) {
            int combined = newValue + limit.getValue();
            if (combined > newMax) {
                newValue = newMax - limit.getValue();
            }
        }
        super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
    }
}

// use
LimitedBoundedRangeModel firstModel = new LimitedBoundedRangeModel(null);
LimitedBoundedRangeModel secondModel = new LimitedBoundedRangeModel(firstModel);
firstModel.limit= secondModel;

JSlider first = new JSlider(firstModel);
JSlider second = new JSlider(secondModel);

単純 (2 つの従属のみ) で粗雑 (直接双方向カップリング) であり、実際には実際には使用できないため、少なくとも機能するはずですが、機能しません - 時々私を襲う驚きの 1 つです。 -) 視覚的な問題は親指の位置です:

  • サムの右側をクリックすると、結合された最大値が尊重されます。サムがしきい値を超えて移動することはありません。
  • ドラッグするとき、UI はモデルの調整を認識しないため、親指をどこにでも移動できます。これは、UI が「ローカル」最大値のみを認識しているためです。
  • ドラッグエンドでは、親指はその無効な位置にとどまります..現在、親指がモデルと同期していないため、バグのようなにおいがします

この誤動作の理由は、Handler の changeListener: ドラッグ時に親指の位置を再計算しないためです (これは問題ありません)。微妙なバグは、モデルの調整プロパティがリセットされた後にのみ内部ドラッグフラグがリセットされるため、最終値に関する最後の通知が欠落していることです...

ハック アラウンドは、調整フラグが true から false に変更された場合に、追加の changeEvent の起動を呼び出すことです。

        boolean invoke =
               (adjusting != getValueIsAdjusting()) && !adjusting;
        super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
        if (invoke) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    fireStateChanged();   
                }
            });
        }
于 2011-09-20T08:36:37.390 に答える