Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8193286

IntegerSpinnerFactory does not wrap value correctly

XMLWordPrintable

    • b14
    • generic
    • generic

      FULL PRODUCT VERSION :
      9.0.1, x86_64: "Java SE 9.0.1" /Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home

      ADDITIONAL OS VERSION INFORMATION :
      Darwin 16.7.0 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 x86_64

      A DESCRIPTION OF THE PROBLEM :
      The IntegerSpinner does not work as expected. The wrap around does not behave correctly.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the provided source code. Step through the spinner values by pressing the UP button. Note, when pressing the DOWN Button the behaviour is correct. I think the bug is in the following implementation:

      static int wrapValue(int value, int min, int max) {
              if (max == 0) {
                  throw new RuntimeException();
              }

              int r = value % max;
              if (r > min && max < min) {
                  r = r + max - min;
              } else if (r < min && max > min) {
                  r = r + max - min;
              }
              return r;
          }

      in the Spinner class (Spinner.java) combined with

       /** {@inheritDoc} */
              @Override public void decrement(int steps) {
                  final int min = getMin();
                  final int max = getMax();
                  final int newIndex = getValue() - steps * getAmountToStepBy();
                  setValue(newIndex >= min ? newIndex : (isWrapAround() ? Spinner.wrapValue(newIndex, min, max) + 1 : min));
              }

              /** {@inheritDoc} */
              @Override public void increment(int steps) {
                  final int min = getMin();
                  final int max = getMax();
                  final int currentValue = getValue();
                  final int newIndex = currentValue + steps * getAmountToStepBy();
                  setValue(newIndex <= max ? newIndex : (isWrapAround() ? Spinner.wrapValue(newIndex, min, max) - 1 : max));
              }

      in SpinnerValueFactory.java in the class IntegerSpinnerValueFactory

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Only values between 2 and 10 are allowed ant the order when pressing up should be: 2, 3, 4, 5, 6, 7, 8, 9, 10, 2, 3, 4, and so on....
      ACTUAL -
      Right now it produces: 2,3,4,5,6,7,8,9,10, 8, 9, 10, 8, 9, 10, 8, 9, 10 and so on....

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package sample;

      import javafx.application.Application;
      import javafx.scene.Scene;
      import javafx.scene.control.Spinner;
      import javafx.scene.control.SpinnerValueFactory.IntegerSpinnerValueFactory;
      import javafx.scene.layout.VBox;
      import javafx.stage.Stage;

      public class Main extends Application {

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

        @Override
        public void start(Stage primaryStage) throws Exception {
          Spinner<Integer> spinner = new Spinner<>();
          IntegerSpinnerValueFactory integerSpinnerValueFactory = new IntegerSpinnerValueFactory(2, 10, 2);
          integerSpinnerValueFactory.setWrapAround(true);
          spinner.setValueFactory(integerSpinnerValueFactory);
          VBox vBox = new VBox();
          vBox.getChildren().setAll(spinner);
          primaryStage.setTitle("Hello World");
          primaryStage.setScene(new Scene(vBox, 300, 275));
          primaryStage.show();
        }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Subclass IntegerSpinnerValueFactory and adapt increment to your needs. In our case, we only need step of size 1, i.e:

      package sample;

      import javafx.scene.control.SpinnerValueFactory.IntegerSpinnerValueFactory;

      public final class IntSpinnerValueFactory extends IntegerSpinnerValueFactory {
        public IntSpinnerValueFactory(final int min, final int max) {
          super(min, max);
        }

        public IntSpinnerValueFactory(final int min, final int max, final int initialValue) {
          super(min, max, initialValue, 1);
        }

        @Override
        public void increment(int steps) {
          final int min = getMin();
          final int max = getMax();
          final int currentValue = getValue();
          final int newIndex = currentValue + steps * getAmountToStepBy();
          setValue(
              newIndex <= max ? newIndex : (isWrapAround() ? min : max));
        }
      }


            kpk Karthik P K
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            7 Start watching this issue

              Created:
              Updated:
              Resolved: