Качели: JSlider, но с грубым / точным управлением?

У меня есть JSlider с 65536 различными значениями. Он отлично подходит для грубых и очень точных настроек (+/-1 с использованием стрелок вверх / вниз), но очень плох в середине.

Есть ли что-нибудь, что было бы лучше? Я смутно представляю себе, как взять 2 ползунка по одному для грубой + точной настройки, но не могу понять, как заставить их работать вместе.

1 ответ

Как насчет использования JSpinner вместо JSlider? С SpinnerNumberModel Вы можете установить размер шага и даже динамически изменять размер шага.

Если у вас все в порядке с несколькими элементами управления, у вас может быть даже два счетчика, один для установки значений, а другой для установки размера шага, используемого первым счетчиком.

Для примера я взял код SliderDemo из учебника по слайдеру Swing и изменил его, чтобы использовать два JSpinners вместо одного JSlider, Вот самая интересная часть кода, которую я изменил:

//Create the slider^H^H^H^H^H^H spinners.
// JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL,
//                                       FPS_MIN, FPS_MAX, FPS_INIT);
final int initStep = 1;
final SpinnerNumberModel animationModel = new SpinnerNumberModel(FPS_INIT,
                                                                 FPS_MIN,
                                                                 FPS_MAX,
                                                                 initStep);
final SpinnerNumberModel stepSizeModel = new SpinnerNumberModel(initStep,
                                                                1,
                                                                10,
                                                                1);
final JSpinner framesSpinner = new JSpinner(animationModel);
framesSpinner.addChangeListener(this);

final JSpinner stepSpinner = new JSpinner(stepSizeModel);
stepSpinner.addChangeListener(new ChangeListener() 
{
    public void stateChanged(ChangeEvent arg0)
    {
        animationModel.setStepSize(stepSizeModel.getNumber());
    } 
});

Мне также пришлось внести несколько менее интересных изменений, таких как создание метки для счетчика размера шага, добавление новой метки и нового счетчика в контейнер и изменение stateChanged() метод на this привести источник события к JSpinner вместо того, чтобы привести его к JSlider,

Конечно, вы могли бы уточнить это далее, например, увеличить размер шага для счетчика размера шага (например, чтобы вы могли изменить размер шага от 1 до 101 одним щелчком мыши). Вы также можете использовать другой элемент управления вместо JSpinner установить размер шага, например поле со списком.

Наконец, чтобы сделать все это действительно простым в использовании, вы, вероятно, захотите подключить некоторые ускорители нажатий клавиш (возможно, через меню?), Чтобы вы могли изменить размер шага, фактически не перемещая мышь или фокус клавиатуры с одного счетчика на другой.,

Изменить: учитывая, что вы должны использовать JSlider независимо от того, знаете ли вы, что вы можете использовать PgUp/PgDn для перемещения вверх и вниз на 1/10 от общего диапазона?

Если вы хотите изменить эту 1/10- ю величину (например, сделать ее динамической), вам нужно переопределить метод BasicSliderUI.scrollByBlock(),

Вот пример, где я просто переопределил класс пользовательского интерфейса JSlider шаг на 1/4 диапазона вместо 1/10:

//Create the slider.
JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL,
                                      FPS_MIN, FPS_MAX, FPS_INIT);
framesPerSecond.setUI(new javax.swing.plaf.metal.MetalSliderUI() {

    private static final int SLIDER_FRACTION = 4;

    /**
     * This code is cut, paste, and modified from
     * {@link javax.swing.plaf.basic.BasicSliderUI#scrollByBlock(int).
     * I should be ashamed of cutting and pasting, but whoever hardcoded the magic
     * number "10" in the original code should be more ashamed than me. ;-) 
     *
     * @param direction
     *          either +1 or -1
     */   
    @Override
    public void scrollByBlock(final int direction) {
        synchronized(slider)    {
            int oldValue = slider.getValue();
            int blockIncrement = (slider.getMaximum() - slider.getMinimum()) / SLIDER_FRACTION;
            if (blockIncrement <= 0 && slider.getMaximum() > slider.getMinimum()) {
                blockIncrement = 1;
            }
            int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
            slider.setValue(oldValue + delta);          
        }
    }
});

Отсюда было бы не сложно заменить эту константу SLIDER_FRACTION с переменной, которая была установлена ​​другим ползунком или счетчиком, не так ли?

Другие вопросы по тегам