【问题标题】:JavaFX Spinner change is slow with click and hold of mouse button单击并按住鼠标按钮,JavaFX Spinner 变化很慢
【发布时间】:2016-12-08 22:37:07
【问题描述】:

单击并按住向上/向下箭头按钮时,Spinner 更新速度很慢。有没有什么办法可以提高变化速度?

当我用鼠标单击、单击、单击时,微调器值的变化与我单击时一样快。如果我在每次按键时使用键盘上的向上/向下箭头或按住向上/向下箭头键,它也会快速变化。当我单击并按住箭头按钮时,我希望值能够快速改变。

有人知道怎么做吗?

【问题讨论】:

    标签: javafx javafx-8


    【解决方案1】:

    SpinnerSkin 中的SpinnerBehavior 每 750 毫秒触发一次更新。不幸的是,如果不使用反射来访问private 成员,就无法简单地设置/修改此行为。因此,在没有反射的情况下做到这一点的唯一方法是使用事件过滤器以更快的速度触发更新:

    private static final PseudoClass PRESSED = PseudoClass.getPseudoClass("pressed");
    
    @Override
    public void start(Stage primaryStage) {
        Spinner<Integer> spinner = new Spinner(Integer.MIN_VALUE, Integer.MAX_VALUE, 0);
    
        class IncrementHandler implements EventHandler<MouseEvent> {
    
            private Spinner spinner;
            private boolean increment;
            private long startTimestamp;
    
            private static final long DELAY = 1000l * 1000L * 750L; // 0.75 sec
            private Node button;
    
            private final AnimationTimer timer = new AnimationTimer() {
    
                @Override
                public void handle(long now) {
                    if (now - startTimestamp >= DELAY) {
                        // trigger updates every frame once the initial delay is over
                        if (increment) {
                            spinner.increment();
                        } else {
                            spinner.decrement();
                        }
                    }
                }
            };
    
            @Override
            public void handle(MouseEvent event) {
                if (event.getButton() == MouseButton.PRIMARY) {
                    Spinner source = (Spinner) event.getSource();
                    Node node = event.getPickResult().getIntersectedNode();
    
                    Boolean increment = null;
                    // find which kind of button was pressed and if one was pressed
                    while (increment == null && node != source) {
                        if (node.getStyleClass().contains("increment-arrow-button")) {
                            increment = Boolean.TRUE;
                        } else if (node.getStyleClass().contains("decrement-arrow-button")) {
                            increment = Boolean.FALSE;
                        } else {
                            node = node.getParent();
                        }
                    }
                    if (increment != null) {
                        event.consume();
                        source.requestFocus();
                        spinner = source;
                        this.increment = increment;
    
                        // timestamp to calculate the delay
                        startTimestamp = System.nanoTime();
    
                        button = node;
    
                        // update for css styling
                        node.pseudoClassStateChanged(PRESSED, true);
    
                        // first value update
                        timer.handle(startTimestamp + DELAY);
    
                        // trigger timer for more updates later
                        timer.start();
                    }
                }
            }
    
            public void stop() {
                timer.stop();
                button.pseudoClassStateChanged(PRESSED, false);
                button = null;
                spinner = null;
            }
        }
    
        IncrementHandler handler = new IncrementHandler();
        spinner.addEventFilter(MouseEvent.MOUSE_PRESSED, handler);
        spinner.addEventFilter(MouseEvent.MOUSE_RELEASED, evt -> {
            if (evt.getButton() == MouseButton.PRIMARY) {
                handler.stop();
            }
        });
    
        Scene scene = new Scene(spinner);
    
        primaryStage.setScene(scene);
        primaryStage.show();
    }       
    

    【讨论】:

    • 感谢费边!我不得不稍微修改一下源代码以降低按住鼠标按钮时递增/递减的速度,但是您的回答为我节省了很多时间!
    【解决方案2】:

    我稍微修改了fabian的答案,以降低按住鼠标时微调器的速度:

    private int currentFrame = 0;
    private int previousFrame = 0;        
    
    @Override
    public void handle(long now)
    {
        if (now - startTimestamp >= initialDelay)
            {
            // Single or holded mouse click
            if (currentFrame == previousFrame || currentFrame % 10 == 0)
            {
                if (increment)
                {
                    spinner.increment();
                }
                else
                {
                    spinner.decrement();
                }
            }
        }
    
        ++currentFrame;
    }
    

    在停止计时器后,我们再次调整 previousFrame:

    public void stop()
    {
        previousFrame = currentFrame;
    
        [...]
    }
    

    【讨论】:

      【解决方案3】:

      对 Fabian 的回答进行了小幅改进。对 MOUSE_RELEASED addEventerFilter 进行以下修改将停止单击与微调器关联的文本字段时导致的 NullPointerException。费边干杯!

          spinner.addEventFilter(MouseEvent.MOUSE_RELEASED, evt -> {
              Node node = evt.getPickResult().getIntersectedNode();
              if (node.getStyleClass().contains("increment-arrow-button") ||
                  node.getStyleClass().contains("decrement-arrow-button")) {
                      if (evt.getButton() == MouseButton.PRIMARY) {
                          handler.stop();
                      }
              }
          });
      

      【讨论】:

      • 我看到你的艺术 ;) 谢谢。
      【解决方案4】:

      在某些情况下,更改更新速度的替代方法可能是调整每次更新的值递增/递减量。

      SpinnerValueFactory.IntegerSpinnerValueFactory intFactory =
      (SpinnerValueFactory.IntegerSpinnerValueFactory) spinner.getValueFactory();
      intFactory.setAmountToStepBy(100);
      

      参考:http://news.kynosarges.org/2016/10/28/javafx-spinner-for-numbers/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-02-04
        • 1970-01-01
        • 1970-01-01
        • 2011-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多