我正在尝试捕获JavaFX Slider上的事件,尤其是指示拖动已停止并已释放的事件。起初我使用了valueProperty
这样的模拟代码
slider.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> ov, Number oldValue, Number newValue) {
log.fine(newValue.toString());
}
});
但有了它,它经常更新。所以我在SceneBuilder和API中进行了搜索,发现了一些类似于
的东西slider.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
@Override
public void handle(MouseDragEvent event) {
System.out.println("setOnMouseDragReleased");
}
});
但他们永远不会被解雇。只有一些像setOnMouseReleased
我得到一些输出,但这例如计算整个节点,如标签等。
所以我的问题是,这是正确的钩子,知道值不再变化(如果可能的话,在发布鼠标之后就像拖动手势一样)并且可能只是一个小例子看其界面有效。
答案 0 :(得分:9)
向滑块的valueChangingProperty添加一个更改侦听器,以了解滑块的值何时发生变化,并对值的变化采取您想要的任何操作。
以下示例将在开始更改时记录滑块的值,并在完成更改时再次记录。
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class SliderChangeLog extends Application {
private final ListView<String> startLog = new ListView<>();
private final ListView<String> endLog = new ListView<>();
@Override public void start(Stage stage) throws Exception {
Pane logsPane = createLogsPane();
Slider slider = createMonitoredSlider();
VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.setPadding(new Insets(10));
layout.getChildren().setAll(
slider,
logsPane
);
VBox.setVgrow(logsPane, Priority.ALWAYS);
stage.setTitle("Slider Value Change Logger");
stage.setScene(new Scene(layout));
stage.show();
}
private Slider createMonitoredSlider() {
final Slider slider = new Slider(0, 1, 0.5);
slider.setMajorTickUnit(0.5);
slider.setMinorTickCount(0);
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
slider.setMinHeight(Slider.USE_PREF_SIZE);
slider.valueChangingProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(
ObservableValue<? extends Boolean> observableValue,
Boolean wasChanging,
Boolean changing) {
String valueString = String.format("%1$.3f", slider.getValue());
if (changing) {
startLog.getItems().add(
valueString
);
} else {
endLog.getItems().add(
valueString
);
}
}
});
return slider;
}
private HBox createLogsPane() {
HBox logs = new HBox(10);
logs.getChildren().addAll(
createLabeledLog("Start", startLog),
createLabeledLog("End", endLog)
);
return logs;
}
public Pane createLabeledLog(String logName, ListView<String> log) {
Label label = new Label(logName);
label.setLabelFor(log);
VBox logPane = new VBox(5);
logPane.getChildren().setAll(
label,
log
);
logPane.setAlignment(Pos.TOP_LEFT);
return logPane;
}
public static void main(String[] args) { launch(args); }
}
答案 1 :(得分:0)
jewelsea的回答非常有助于让我走上正轨,但是如果&#34; snapToTicks&#34;是开启,不良行为的结果。 &#34;结束&#34; jewelsea&#39> s侦听器捕获的值是之前快照发生的时间,并且永远不会捕获捕捉后的值。
我的解决方案在value
上设置了一个监听器,但使用valueChanging
作为哨兵。类似的东西:
slider.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(
ObservableValue<? extends Number> observableValue,
Number previous,
Number now) {
if (!slider.isValueChanging()
|| now.doubleValue() == slider.getMax()
|| now.doubleValue() == slider.getMin()) {
// This only fires when we're done
// or when the slider is dragged to its max/min.
}
}
});
我发现检查最大值和最小值是必要的,以便捕获角落情况,用户在放开鼠标之前将滑块一直拖过其左边界或右边界。出于某种原因,这并没有引发像我期待的那样的事件,所以这似乎是一个好的解决方法。
注意:与jewelsea不同,为了简单起见,我忽略了起始值。
注2:我实际上使用的是ScalaFX 2,所以我不确定这个Java翻译是否按编写方式编译。
答案 2 :(得分:0)
有时您可能想知道用户何时移动滑块,而滑块值却由于绑定到属性而发生了变化。一个示例是在媒体播放器视图上用于显示媒体时间轴的滑块。滑块不仅显示时间,而且还允许用户快进或快退。滑块绑定到媒体播放器的当前时间,从而触发滑块上的更改值。如果用户移动滑块,则可能需要检测拖动以停止媒体播放器,让媒体播放器搜索新时间并继续播放。不幸的是,似乎在滑块上触发的唯一拖动事件是setOnDragDetected事件。因此,我使用以下两种方法来检查滑块拖动。
slider.setOnDragDetected(new EventHandler<Event>() {
@Override
public void handle(Event event) {
currentPlayer.pause();
isDragged=true;
}
});
slider.setOnMouseReleased(new EventHandler<Event>() {
@Override
public void handle(Event event) {
if(isDragged){
currentPlayer.seek(Duration.seconds((double) slider.getValue()));
currentPlayer.play();
isDragged=false;
}
}
});