Страницы

Поиск по вопросам

пятница, 30 ноября 2018 г.

Выполнять действие пока нажата кнопка

Нужна кнопка нажав, на которую можно выполнить действие и если кнопка зажата дальше чем, скажем, 200 мс., то выполнять действие до тех пор, пока кнопка не будет отпущена. Но оказывается не все так просто. Я не могу просто написать в вызове что-то вроде:
if(pressed){ Thread.sleep(100); doIt(); }
Это остановит поток пользовательского интерфейса. Значит это надо перенести в другой поток.
То есть, по нажатию кнопку должен создаваться новый поток, который будет следить за тем нажата ли кнопка, сколько прошло времени,выполнять нужное действие.
К тому же, обязательно придется проследить чтобы поток был завершен вместе с закрытием приложения и т.д.
Может есть другие разумные способы решить данную задачу? Идеально если бы был какой-то функционал отложенной задачи, по типу __Platform.runLater__ , но только выполнить задачу через 100 мс, но я ничего подобного не нашел.


Ответ

Написал вот такую вот конструкцию.
private Thread pressingThread;
@FXML void onPress() { System.out.println("do something"); final int initDelay = 200; final int repeatDelay = 50; pressingThread = new Thread(() -> { try { Thread.sleep(initDelay); while (true) { Platform.runLater(() -> System.out.println("do something again")); Thread.sleep(repeatDelay); } } catch (InterruptedException ignored) { } }); pressingThread.setDaemon(true); pressingThread.start(); }
@FXML void onRelease() { pressingThread.interrupt(); }
Создается поток, который ждет необходимое время, потом в бесконечном цикле передает управление в поток пользовательского интерфейса нужное действие. Чтобы завершить работу необходимо вызывать метод interrupt().
Пробовал реализовать через переменную pressed, которая хранила бы состояние кнопки, и потом проверять не зажата ли кнопка, но тут есть тонкость, что если быстро нажать дважды на кнопку, то можно создать два потока, которые будут думать что кнопка не была отпущена. Потому все равно придется использовать interrupt()
Ред. Переписал в более удобный вид
import javafx.application.Platform;
public class DoWhilePressed { private int initDelay = 200; private int repeatDelay = 50; private Runnable doWhilePressed = ()->{};
private Thread pressingThread;
private pressed = false; public void press(){ if(pressed)return; pressed = true; doWhilePressed.run(); pressingThread = new Thread(() -> { try { Thread.sleep(initDelay); while (true) { Platform.runLater(() -> doWhilePressed.run()); Thread.sleep(repeatDelay); } } catch (InterruptedException ignored) { } }); pressingThread.setDaemon(true); pressingThread.start(); }
public void release(){ pressed = false; pressingThread.interrupt(); }
public int getInitDelay() { return initDelay; }
public DoWhilePressed setInitDelay(int initDelay) { this.initDelay = initDelay; return this; }
public int getRepeatDelay() { return repeatDelay; }
public DoWhilePressed setRepeatDelay(int repeatDelay) { this.repeatDelay = repeatDelay; return this; }
public Runnable getDoWhilePressed() { return doWhilePressed; }
public DoWhilePressed setDoWhilePressed(Runnable doWhilePressed) { this.doWhilePressed = doWhilePressed; return this; } }
Использовать можно как
private DoWhilePressed doWhilePressed = new DoWhilePressed() .setInitDelay(300) .setRepeatDelay(30) .setDoWhilePressed(() -> System.out.println("pressed"));
@FXML void onPress() { doWhilePressed.press(); }
@FXML void onRelease() { doWhilePressed.release(); }

Комментариев нет:

Отправить комментарий