Связанные JSliders с максимальным комбинированным значением

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

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

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

Я надеюсь в этом есть смысл. Спасибо за помощь.


person Peter    schedule 19.09.2011    source источник
comment
Вы ищете Java-слайдер с несколькими пальцами, например как MultiSlider?   -  person trashgod    schedule 19.09.2011
comment
Я ищу расположение ползунков, визуально похожее на эквалайзер, с максимальным комбинированным значением.   -  person Peter    schedule 19.09.2011


Ответы (2)


"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();   
                }
            });
        }
person kleopatra    schedule 20.09.2011
comment
+1 анализ! Питер: Чтобы получить желаемый эффект, я думаю, будет необходимо реализовать один слайдер с несколькими ползунками с соответствующей моделью с несколькими диапазонами. Вот руководство по сантехнике. - person trashgod; 27.09.2011
comment
+1 некоторое время назад наткнулся на ту же проблему, но пока не смог ее решить. Кстати: более оригинальной цитатой было бы Nichts leichter als das, komm mit. хотя, возможно, только известно немногим ;-). - person Howard; 28.09.2011
comment
@ Ховард, ты прав - моя память заржавела (und wird nicht mehr augefrischt seit Sandmännchen's Sendeplatz verlegt wurde :-) - person kleopatra; 01.10.2011
comment
Кажется, я забыл принять ответ на этот вопрос (исправлено). Спасибо за тщательный анализ! - person Peter; 18.10.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();
person Gabriel Negut    schedule 20.09.2011