Linked JSliders With Maximum Combined Value

倾然丶 夕夏残阳落幕 提交于 2019-12-04 18:24:11

"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();   
                }
            });
        }

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