Linked JSliders With Maximum Combined Value

不羁岁月 提交于 2020-01-13 06:56:10

问题


What's the best way to 'link' JSliders to put a cap on the combined value?

Imagine a fighting game where the user can specify character traits like speed, agility, endurance and accuracy. The user is given 100 points to allocate however he chooses, but the total value of all the sliders must not exceed 100. That is, the sliders should not allow such increases.

If the user has allocated 30 points each to speed, agility and endurance, then the slider for accuracy should allow a maximum of 10 points (because 30 + 30 + 30 + 10 = 100). Notwithstanding, the range of the each slider should remain unchanged (in this case, 0 to 100).

I hope this makes sense. Thanks for the help.


回答1:


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

Basically, all such enhanced functionality must be implemented in the model: for JSlider, that's a BoundedRangeModel. Implement/extend and enforce its value to respect the "combined" max. Something like

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

While simple (two dependents only) and crude (direct bidirectional coupling) and as such not really usable out in the wild, it should at least work ... but doesn't - one of those surprises which hit me from time to time ;-) The visual problem is the thumb-position:

  • the combined max is respected when clicking to the right of the thumb: the thumb never moves over the threshhold
  • when dragging, the thumb can be moved everywhere which might be expected, as the ui isn't aware of the model tweak - it knows only the "local" max
  • on drag-end, the thumb remains at that invalid position.. which smells like a bug as now the thumb is out-off synch with the model

The reason for this misbehaviour is that the changeListener in Handler: it doesn't recalculate its thumb position when dragging (which is okay). The subtle bug is, that the internal dragging flag is only reset after the model's adjusting property is reset, so missing the very last notification about the final value ...

Hack around is to invoke the firing of an additional changeEvent, if the adjusting flag changes from true to false

        boolean invoke =
               (adjusting != getValueIsAdjusting()) && !adjusting;
        super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
        if (invoke) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    fireStateChanged();   
                }
            });
        }



回答2:


Create 4 sliders and some variables: the maximum total value (say, 100) and the current total (0).

When the value of any of the sliders modifies, do:

// I hope my logic isn't failing me at this point

if (slider.getValue() > (maxTotal - currentTotal))
    slider.setValue(maxTotal - currentTotal);

currentTotal = slider1.getValue() + slider2.getValue()
             + slider3.getValue() + slider4.getValue();


来源:https://stackoverflow.com/questions/7468314/linked-jsliders-with-maximum-combined-value

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!