Вопрос JSlider: позиция после левого щелчка

Всякий раз, когда я нажимаю JSlider, он позиционирует один majorTick в направлении щелчка, а не прыгает на место, которое я на самом деле нажимаю. (Если ползунок находится в точке 47, и я нажимаю 5, он будет прыгать до 37 вместо 5). Есть ли способ изменить это при использовании JSliders, или мне нужно использовать другую структуру данных?

Ответы

Ответ 1

Как ни странно, это может выглядеть как Look and Feel, который контролирует это поведение. Взгляните на BasicSliderUI, метод, который вам нужно переопределить, scrollDueToClickInTrack(int).

Чтобы установить значение JSlider до ближайшего значения до того места, где пользователь нажал на дорожку, вам нужно будет сделать какой-то причудливый перевод брюк между координатами мыши от getMousePosition() до действительного значения дорожки, принимая во внимание положение Component, его ориентацию, размер и расстояние между тиками и т.д. К счастью, BasicSliderUI дает нам две удобные функции: valueForXPosition(int xPos) и valueForYPosition(int yPos):

JSlider slider = new JSlider(JSlider.HORIZONTAL);
slider.setUI(new MetalSliderUI() {
    protected void scrollDueToClickInTrack(int direction) {
        // this is the default behaviour, let comment that out
        //scrollByBlock(direction);

        int value = slider.getValue(); 

        if (slider.getOrientation() == JSlider.HORIZONTAL) {
            value = this.valueForXPosition(slider.getMousePosition().x);
        } else if (slider.getOrientation() == JSlider.VERTICAL) {
            value = this.valueForYPosition(slider.getMousePosition().y);
        }
        slider.setValue(value);
    }
});

Ответ 2

Этот вопрос старый, но я сам столкнулся с этой проблемой. Это мое решение:

JSlider slider = new JSlider(/* your options here if desired */) {
    {
        MouseListener[] listeners = getMouseListeners();
        for (MouseListener l : listeners)
            removeMouseListener(l); // remove UI-installed TrackListener
        final BasicSliderUI ui = (BasicSliderUI) getUI();
        BasicSliderUI.TrackListener tl = ui.new TrackListener() {
            // this is where we jump to absolute value of click
            @Override public void mouseClicked(MouseEvent e) {
                Point p = e.getPoint();
                int value = ui.valueForXPosition(p.x);

                setValue(value);
            }
            // disable check that will invoke scrollDueToClickInTrack
            @Override public boolean shouldScroll(int dir) {
                return false;
            }
        };
        addMouseListener(tl);
    }
};

Ответ 3

Это поведение происходит от ОС. Вы уверены, что хотите переопределить его и запутать пользователей? Я так не думаю.;)