JavaFX 8: how to add a timedelay to a listener?

2019-01-15 16:59发布

问题:

I'm working on an JavaFX 8 app right now, where i have a tableView and some textFields above which make it possible to search/filter for certain columns in the tableView. I have added a listener to the textFields, to trigger the filtering automatically when a change is detected. I used the code below to do this.

textField_filterAddress.textProperty().addListener((observable, oldValue, newValue) -> {
            doSomething(); // in this case, filter table data and refresh tableView afterwards
        });

My question now is: what's the easiest way to integrate some kind of time delay, before the filtering gets triggered? I'd like to wait a few milliseconds, because everytime the user is filtering it's executing a new database query and i don't think this is necessary for every single char that the user puts in. I'd rather wait until he/she finished his input. Is there some kind of feature like this already built into the whole listener thing? Or do i have to implement my own solution? If so, how? I thought about some kind of concurrency solution, so the rest of the software won't freeze during the waiting period. But i thought i'd ask here if there is an easier solution before thinking too much about my own way...

Big thanks in advance!

回答1:

The code below will schedule to do something after a 1 second delay from the last time a text field changes. If the text field changes within that 1 second window, the previous change is ignored and the something is scheduled to be done with the new value 1 second from the most recent change.

PauseTransition pause = new PauseTransition(Duration.seconds(1));
textField.textProperty().addListener(
    (observable, oldValue, newValue) -> {
        pause.setOnFinished(event -> doSomething(newValue));
        pause.playFromStart();
    }
);

I didn't test this, but it should work :-)

A more sophisticated solution might be to make use of a "forgetful" ReactFX suspendable event stream. ReactFX based solutions are discussed in the related question:

  • Wait before Reacting to a Property Change JavaFX 8


回答2:

Interesting problem, and one which I'm sure others have dealt with. I'm thinking this through for the first time and don't know how practical this suggestion is, but here goes:

Have your text field listeners send a notification to a queue. Then, use a util.TimerTask method that executes at your preferred time interval to process the queue, and use that to build a new filter (or not).

The wait time in the above could be rather varied, so to make it a bit more consistent, send the text field ID with a time stamp and have the Timer run more frequently and only process the new filter if a certain amount of time has elapsed.

There are various concurrency-safe queues that could be used to house the data.