Качели: 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
с переменной, которая была установлена другим ползунком или счетчиком, не так ли?