Связанные JSliders с максимальным комбинированным значением - PullRequest
1 голос
/ 19 сентября 2011

Какой лучший способ «связать» JSliders, чтобы поставить верх над комбинированным значением?

Представьте себе игру-бой, в которой пользователь может указать такие черты характера, как скорость, ловкость, выносливость и точность.Пользователю дается 100 баллов для распределения по своему усмотрению, но общая стоимость всех ползунков не должна превышать 100. То есть ползунки не должны допускать такого увеличения.

Если пользователь назначил по 30 баллов каждыйДля скорости, ловкости и выносливости, то ползунок для точности должен позволять максимум 10 баллов (потому что 30 + 30 + 30 + 10 = 100).Несмотря на это, диапазон каждого ползунка должен оставаться неизменным (в данном случае от 0 до 100).

Надеюсь, это имеет смысл.Спасибо за помощь.

Ответы [ 2 ]

5 голосов
/ 20 сентября 2011

"nichts einfacher als das" - dachte ... (вставить название: -)

По сути, все такие расширенные функциональные возможности должны быть реализованы в модели: для 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);

Хотя простой (только два иждивенца) и грубый (прямая двунаправленная связь) и, как таковой, на самом деле не может использоваться в дикой природе, он должен по крайней мере работать ... но не работает - один из тех сюрпризов, которые поразили меня со временем ко времени ;-) Визуальная проблема заключается в положении большого пальца:

  • комбинированный максимум учитывается при нажатии справа от большого пальца: большой палец никогда не перемещается по порогу
  • при перетаскивании, большой палец можно перемещать везде, чего и следовало ожидать, поскольку пользовательский интерфейс не знает о подстройке модели - он знает только «локальный» максимум
  • на конце перетаскивания большой палец остается в этом недопустимом положении ... которое пахнет жуком, поскольку теперь большой палец не синхронизирован с моделью

Причиной этого неправильного поведения является то, что changeListener в Handler: он не пересчитывает свою позицию большого пальца при перетаскивании (что нормально). Тонкая ошибка в том, что внутренний флаг перетаскивания сбрасывается только после , а свойство настройки модели сбрасывается, поэтому отсутствует самое последнее уведомление о конечном значении ...

Обходной путь - вызвать срабатывание дополнительного changeEvent, если корректирующий флаг меняется с true на false

        boolean invoke =
               (adjusting != getValueIsAdjusting()) && !adjusting;
        super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
        if (invoke) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    fireStateChanged();   
                }
            });
        }
0 голосов
/ 20 сентября 2011

Создайте 4 ползунка и некоторые переменные: максимальное общее значение (скажем, 100) и текущее общее (0).

Когда значение любого из ползунков изменяется, выполните:

// 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();
...