【问题标题】:JavaFX 2.2: Hooking Slider Drag n Drop EventsJavaFX 2.2:挂钩滑块拖放事件
【发布时间】:2013-09-19 10:20:29
【问题描述】:

我正在尝试捕捉 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 我得到一些输出,但是这对于 whole 节点如标签等的计数。

所以我的问题是,这是知道值不再变化的正确钩子(如果可能在释放鼠标后,如拖放手势),也许还有一个小例子来查看它的界面工作。

【问题讨论】:

    标签: events drag-and-drop slider javafx-2


    【解决方案1】:

    向滑块的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 :) 你知道如何手动更改滑块刻度距离吗?就像我想要 2 4 8 16 32 等的刻度一样
    • @thatsIch 提出一个关于滑块刻度距离的新问题
    • thatslch 的新问题是Configuring Slider ticks manually。
    • 太好了,这对我也有帮助,谢谢!但我可以问一下,如果不是,那么“setOnMouseDragReleased”事件应该对什么有用?他们什么时候开火?
    • setOnMouseDragReleased 允许您在用户单击鼠标、按住鼠标、移动鼠标​​并稍后释放鼠标时拦截事件。它是一个相对较低级别的 API,用于在您的应用程序中实现自定义拖动处理程序。在这种情况下,没有必要使用 setOnMouseDragReleased。一个示例用法是通过绘画应用程序中的拖动手势实现自定义选择矩形。在大多数情况下,将使用 drag and drop api 代替 setOnMouseDragReleased 方法。
    【解决方案2】:

    有时您可能想知道用户何时移动滑块,而滑块值因绑定到属性而发生变化。一个示例是在媒体播放器视图上使用的滑块以显示媒体时间线。滑块不仅显示时间,还允许用户快进或快退。滑块绑定到媒体播放器的当前时间,这会触发滑块上的更改值。如果用户移动滑块,您可能想要检测拖动以停止媒体播放器,让媒体播放器寻找新的时间并继续播放。不幸的是,似乎在滑块上触发的唯一拖动事件是 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;
                }       
            }
        });
    

    【讨论】:

      【解决方案3】:

      jewelsea 的回答对让我走上正轨非常有帮助,但是如果打开“snapToTicks”,则会导致不良行为。 Jewelsea 的侦听器捕获的“结束”值是在快照发生之前,而从不捕获快照后的值。

      我的解决方案在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.
                  }
              }
          });
      

      我发现检查最大值和最小值对于捕捉用户在放开鼠标之前将滑块一直拖动到其左侧或右侧边界的极端情况是必要的。出于某种原因,这不会像我期望的那样触发事件,所以这似乎是一个不错的解决方法。

      注意:与珠宝海不同,为了简单起见,我忽略了起始值。

      注意 2:我实际上使用的是 ScalaFX 2,所以我不确定这个 Java 翻译是否按原样编译。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-24
        • 1970-01-01
        • 2011-05-16
        • 1970-01-01
        • 2012-05-28
        • 2019-06-13
        • 1970-01-01
        相关资源
        最近更新 更多