@MicroKlizma

Как заставить кнопку в JavaFX ничего не делать?

Имеется кнопка, которая обрабатывает более-менее весомое по времени событие. В моем случае, она в JavaFX приложении при нажатии каждый раз отображает новую капчу. К кнопке привязан метод типа onAction из контроллера, в нем все это происходит. Я хочу, чтобы если я нажимал на кнопку один раз, а потом сразу же второй, то пока метод после первого нажатия еще не завершит свою работу, второй метод не вызывался. Допустим, в самом конце метода я вывожу в консоль слово "конец", и нужно, чтобы я мог нажимать на кнопку сколько угодно раз, пока не увижу это слово, и чтобы при этом ничего не происходило. Я пробовал по классике поставить флаг, типа в начале метода сделать
if (buttonIsPressed) return;
И после него buttonIsPressed = true а в конце всего buttonIsPressed = false
Но это не помогло. Я так понимаю, что эти методы имеют свойство как бы накапливаться, может добавляются в очередь, а потом исполняются один за другим, и вот сколько раз я нажму на кнопку, столько раз метод потом будет срабатывать. Если я нажимал на кнопку 10 раз за пару секунд, то по после того, как я закончил клацать, картинка капчи еще раз 5 поменялась, и продолжалось это длиться тоже где-то пару секунд, короче нежелательно, чтобы такое происходило. Я пишу приложение для себя, в целях изучения, то есть можно и так оставить, но душа хочет чтобы было идеально

Какие тут могут быть методы решения? Я подумал, что может быть нужно как-то создавать второй поток, и тогда все будет выполняться одновременно, параллельно, а не последовательно, а может просто поставить какую-то задержку, таймер на кнопку между нажатиями, но не знаю как это все реализовать. А может быть в JavaFX уже есть готовый какой-нибудь объект, метод, который мне поможет, и не нужно ничего придумывать? Не знаю
  • Вопрос задан
  • 495 просмотров
Решения вопроса 1
@MicroKlizma Автор вопроса
Благодаря комментам под вопросом и некоторому гуглению разобрался что к чему. Я решил проблему путем создания нового потока. Таким образом, поток будет работать параллельно с основным потоком. И в то время пока кнопка существует, параллельно и независимо другой поток может ей управлять. При нажатии на кнопку я вызываю метод onAction(), в котором создаю новый поток с точкой входа в виде метода, который все должен обрабатывать
public void onAction() throws InterruptedException {
        Thread thread = new Thread(this::someMethod);
        thread.start();
    }

Далее делаем в этом методе все, что хотели делать, но при этом, пока выполняется код, делаем кнопку неактивной: button.setDisable(true). Благодаря этому она меняет цвет и пропадает возможность по ней кликать (также вроде можно модифицировать ее стиль в этом состоянии в css файле: .button:disabled)
public void someMethod() {
        button.setDisable(true);
        //code
        button.setDisable(false);
    }

Это решение у меня работало нормально и так, как я хотел. Но оно вызывает исключение, хотя на него можно забить если обернуть в try catch, все равно будет работать:
Exception in thread "Thread-3" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
Я считаю, что хороший программист должен с исключениями бороться :)
Как я понял, исключение выбрасывается тогда, когда меняется вид (UI), элементы (узлы) (node) приложения. Видимо, это можно делать только в FX applicaton thread. В моей программе я изменял текстовое поле и поле с изображением. И решение есть - делать все эти изменения с помощью Platform.runLater(). В него, так же как и при создании Thread, передается объект типа Runnable. Runnable - это функциональный интерфейс, поэтому вместо того, чтобы создавать целый класс, реализующий Runnable, для краткой записи воспользуемся лямбда-выражениями. В моем случае для моего приложения метод будет выглядеть примерно так:
public void someMethod() {
        button.setDisable(true);
        //some code
        Platform.runLater( () -> textField.setText(text) );
        //some code
        Platform.runLater( () -> imageView.setImage(image) );
        //some code
        button.setDisable(false);
    }

Интересно, что setDisable() по идее тоже нужно оборачивать в Platform.runLater(). Но я протестировал, программа срабатывала без исключений даже если не обернуть, хотя казалось бы, этот метод заставляет кнопку менять цвет и делает ее неактивной, некликабельной, меняет состояние кнопки (кстати узнать это состояние можно с помощью isDisabled()), но нет, все работает
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы