在响应属性更改JavaFX 8之前等待

时间:2014-03-07 23:58:27

标签: javafx-8

有没有办法继续监听属性更改,几秒钟,然后触发事件(调用方法)?

例如,当用户在文本字段中输入数据时:

textField.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> arg0, String arg1, String arg2) {
        //before calling a method to do something.. wait for a few seconds ...
        }
    }); 

方案将基于字符串值触发操作。例如,按“M”表示移动,或“MA”表示屏蔽。我想在继续采取行动之前“继续听”2秒钟。

3 个答案:

答案 0 :(得分:4)

正如杰弗里指出的那样,你可以使用ReactFX

EventStreams.valuesOf(textField.textProperty())
        .successionEnds(Duration.ofSeconds(2))
        .subscribe(s -> doSomething(s));

答案 1 :(得分:2)

有几种方法可以解决这个问题。

通常我会推荐Java Timer API,但如果通过“制作动作”暗示更新FX线程上的内容,则必须同步线程,这很麻烦。

根据您的使用情况,您可以使用转换或FX中的时间轴。

以下是转换的示例:

包裹申请;

import javafx.animation.RotateTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
import javafx.util.Duration;

public class TransitionedInputExample extends Application {
  @Override
  public void start(final Stage stage) {
    final ImageView spinner =
        new ImageView("https://cdn1.iconfinder.com/data/icons/duesseldorf/16/process.png");
    spinner.setVisible(false);

    final Label title = new Label("Timed Action Commander Example", spinner);
    title.setContentDisplay(ContentDisplay.BOTTOM);
    title.setFont(Font.font("Helvetica", FontWeight.BOLD, FontPosture.REGULAR, 16));

    final TextField textInput = new TextField();
    textInput.setPromptText("Enter command");

    final TextArea textOutput = new TextArea();
    textOutput.setPromptText("Command results will show up here");

    final VBox layout = new VBox(title, textInput, textOutput);
    layout.setSpacing(24);

    // setup some transition that rotates an icon for 2 seconds
    final RotateTransition rotateTransition = new RotateTransition(Duration.seconds(1), spinner);
    rotateTransition.setByAngle(90);
    // delay rotation so that user can type without being distracted at once
    rotateTransition.setDelay(Duration.seconds(1));

    // restart transition on user input
    textInput.textProperty().addListener((observable, oldText, newText) -> {
      spinner.setVisible(true);
      rotateTransition.playFromStart();
    });

    rotateTransition.setOnFinished((finishHim) -> {
      // execute command
        textOutput.setText("Executing " + textInput.getText());
        spinner.setVisible(false);
      });


    final Scene scene = new Scene(layout);
    stage.setScene(scene);
    stage.show();
  }

  public static void main(final String[] args) {
    launch(args);
  }
}

对于使用时间轴的解决方案,请参阅this post

答案 2 :(得分:1)

您可以考虑使用Inhibeans。它允许您阻止事件的处理,直到您希望触发更改事件。整个ReactFX项目也可能有用,因为您需要做的基本上是构建事件的状态机。您正在寻找像正则表达式这样的事件中的模式。

例如,假设您使用'M'表示移动,使用'MA'表示遮罩。通过状态机,您将拥有两条路径。

中号

M - &gt;甲

然后,您可以使用计时器来确定在处理事件之前等待事件堆积的时间。

结帐sample copied from the ReactFX site

reduceSuccessions

累积紧密时间序列中发出的事件为一个。

EventSource<Integer> source = new EventSource<>();
EventStream<Integer> accum = source.reduceSuccessions((a, b) -> a + b, Duration.ofMillis(200));

source.push(1);
source.push(2);
// wait 150ms
source.push(3);
// wait 150ms
source.push(4);
// wait 250ms
source.push(5);
// wait 250ms

在上面的示例中,在前一个之后的200ms内发出的事件被累积(添加)到前一个事件。 accum会发出以下值:10,5。