постоянно меняющийся JSlider, событие взаимодействия с пользователем?

В настоящее время я работаю над небольшим MP3-плеером с Java Swing. Я хочу реализовать индикатор выполнения, который позволяет пользователю переходить к случайной позиции. Я подумал, что использование JSlider может быть лучшим вариантом.

Теперь проблема в том, что я использую Swing Timer для обновления индикатора выполнения каждые 200 м. Таким образом, событие изменения ползунка срабатывает каждый раз. Есть ли способ отфильтровать вызовы событий, которые не были вызваны пользователем?

В настоящее время я пытаюсь использовать setValueIsAdjusting(true) в таймере, но это кажется очень непоследовательным...

Timer progressTimer = new Timer(200, e -> {
    updateProgress(player.getPosition());
});
progressTimer.start();

progressSlider.addChangeListener(new ChangeListener() {
    @Override
    public void stateChanged(ChangeEvent e) {
        if (progressSlider.getValueIsAdjusting()) {
            return;
        }
        System.out.println("Skipping to "+progressSlider.getValue());
        player.skipTo(progressSlider.getValue());
    }
});

System.out иногда печатает позицию, на которую щелкнул пользователь, иногда позицию, которую ползунок обновил с помощью таймера. Любая помощь?


person Felk    schedule 11.12.2014    source источник
comment
почему вы не можете обновить индикатор выполнения внутри события stateChanged?   -  person Madhawa Priyashantha    schedule 11.12.2014
comment
Привет! Пробовали ли вы написать свой собственный класс модели, расширяющий BoundedRangeModel и передать его конструктору JSpinner? Вы можете заставить модель получать информацию от самого игрока, поэтому вам больше не понадобится таймер.   -  person Tabaqui    schedule 11.12.2014
comment
Спасибо, Табаки. Я посмотрел и не понял, что именно вы имеете в виду. Переопределение внутренних методов, похоже, мне не помогает.   -  person Felk    schedule 12.12.2014


Ответы (2)


Я всегда решал это для JSliders с помощью частного логического флага. Непосредственно перед программной установкой значения JSlider я установил для флага значение true. В начале кода события JSlider я сразу возвращаюсь, если флаг верен.

Установка флага в false является сложной частью, потому что, если вы сделаете это сразу после программной установки значения JSlider, событие изменения еще даже не будет выполнено, поэтому, когда оно действительно выполняется, флаг будет ложным, и ничего не будет. получил.

Выдержка из JavaDocs SwingUtilities.invokeLater():

«Если invokeLater вызывается из потока диспетчеризации событий [...], он все равно будет отложен до тех пор, пока не будут обработаны все ожидающие события».

Поскольку вы уже находитесь в AWT EDT, и цель состоит в том, чтобы позволить JSlider реагировать на изменение (и немедленно вернуться), а затем затем установить флаг в false, решение гениально простое и имеет никогда не подводил меня:

ignoreEvents = true;
jSlider.setValue(newValue);
SwingUtilities.invokeLater(() -> ignoreEvents = false);


РЕДАКТИРОВАТЬ:

Если ситуация действительно проста (вы хотите игнорировать только одно событие), вы можете сделать это:

Как и выше, установите логический флаг перед вызовом setValue. В коде события JSlider, если флаг установлен, очистить флаг и вернуться. Здесь не требуется SwingUtilities.invokeLater().



person Dreamspace President    schedule 16.10.2015
comment
Я больше не в состоянии это проверить, но звучит умно и многообещающе. Я отмечу это как решение, хотя, спасибо! - person Felk; 16.10.2015
comment
Спасибо, мое первое принятое решение. : D Кстати, я не проверял это на системах, отличных от Windows, но цитируемая мной документация предполагает надежное поведение. - person Dreamspace President; 18.10.2015

Я решил проблему, только обновив ползунок через таймер, если он не настраивается:

Timer progressTimer = new Timer(200, e -> {
    if (!progressSlider.getValueIsAdjusting()) {
        updateProgress(player.getPosition());
    }
});
progressTimer.start();

progressSlider.addChangeListener(new ChangeListener() {
    @Override
    public void stateChanged(ChangeEvent e) {
        if (progressSlider.getValueIsAdjusting()) {
            return;
        }
        System.out.println("Skipping to "+progressSlider.getValue());
        player.skipTo(progressSlider.getValue());
    }
});
person Felk    schedule 12.12.2014