Wrote just such a design.
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(); }
A thread is created that waits for the required time, then, in an infinite loop, transfers control to the UI thread the desired action. To shut down, you must call the interrupt () method.
I tried to implement through the pressed variable, which would keep the state of the button, and then check if the button is pressed, but there is a subtlety, that if you quickly press the button twice, you can create two threads that will think that the button was not released. Therefore, you still have to use interrupt () .
Ed. Rewrote in a more convenient form.
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; } }
You can use as
private DoWhilePressed doWhilePressed = new DoWhilePressed() .setInitDelay(300) .setRepeatDelay(30) .setDoWhilePressed(() -> System.out.println("pressed")); @FXML void onPress() { doWhilePressed.press(); } @FXML void onRelease() { doWhilePressed.release(); }