Class SliderTicks<N extends Number>

java.lang.Object
swingtree.api.model.SliderTicks<N>
Type Parameters:
N - The number type of the slider, which is also the type of every spacing and label position.

public final class SliderTicks<N extends Number> extends Object
An immutable value describing the tick marks and the labels along a slider: where the major and minor tick marks are, whether they are drawn, whether the knob snaps to them, and which labels are shown at which numbers. Hand one of these to a slider through UIForSlider.withTicks(SliderTicks), or bind a property holding one through UIForSlider.withTicks(sprouts.Val):

  UI.slider(UI.Axis.HORIZONTAL, 0, 100, volume)
  .withTicks(
      SliderTicks.of(Integer.class)
      .withMajorSpacing(25)
      .withMinorTicksBetween(4)
      .withLabelsAtMajorTicks( v -> v + "%" )
  );
  
This slider draws a major tick mark at 0, 25, 50, 75 and 100, labelled "0%", "25%", "50%", "75%" and "100%", and four minor tick marks between each pair of major tick marks, which puts a minor tick mark at every multiple of 5.

Numbers in the slider's own type

Every spacing and every label position is a number of the same type as the value of the slider, which is the N of this class. A slider for a Double property therefore has its tick marks declared in Doubles:

  UI.slider(UI.Axis.HORIZONTAL, 0.0, 1.0, opacity)
  .withTicks(
      SliderTicks.of(Double.class)
      .withMajorSpacing(0.25)
      .withTickMarksVisible(false)
      .withLabelsAtMajorTicks( v -> Math.round(v * 100) + "%" )
  );
  
A plain JSlider only knows whole numbers, so SwingTree maps fractional numbers onto a range of whole numbers behind the scenes. It chooses that range so that every tick mark lands exactly on one of its whole numbers.

Counting starts at the minimum

Tick marks, and the labels at the major tick marks, count from the minimum of the slider. On a slider running from 3 to 97 with a major spacing of 25, the major tick marks sit at 3, 28, 53 and 78. This is how BasicSliderUI, which the look and feels of Swing build on, draws tick marks, and a label is only useful where its tick mark is. A label which has to sit somewhere else can be placed at any number through withLabelAt(Number, String).

It is a value

Every method which sounds like it changes something returns a new SliderTicks, leaving the one you called it on untouched. Two instances describing the same tick marks and labels are equals(Object) to each other, which is how a slider bound to a property holding a SliderTicks knows whether anything actually changed. A label text function is compared by identity, so a method reference or a lambda which captures nothing is equal to itself every time it is evaluated.

Since this value holds no Swing component, it is safe to keep in a view model and to hand from the application thread to the UI thread. To declare a property of it, use classTyped(Class):


  Val<SliderTicks<Integer>> ticks = showTicks.viewAs(
      SliderTicks.classTyped(Integer.class),
      show -> show ? SliderTicks.of(Integer.class).withMajorSpacing(10) : SliderTicks.of(Integer.class)
  );
  
  • Method Details

    • of

      public static <N extends Number> SliderTicks<N> of(Class<N> numberType)
      Creates a description of no tick marks and no labels for a slider whose value is of the given number type. This is where every SliderTicks starts out:
      
        SliderTicks.of(Integer.class).withMajorSpacing(10)
        
      The supported number types are Integer, Long, Short, Byte, Float and Double, which are also the number types a slider can be bound to.
      Type Parameters:
      N - The number type of the slider.
      Parameters:
      numberType - The type of the value of the slider, and therefore of every spacing and label position.
      Returns:
      A SliderTicks with no tick marks and no labels.
      Throws:
      NullPointerException - If numberType is null.
      IllegalArgumentException - If numberType is not one of the supported number types.
    • classTyped

      public static <N extends Number> Class<SliderTicks<N>> classTyped(Class<N> numberType)
      An alternative to SliderTicks.class which keeps the number type in the type signature, so that you can declare a property holding a SliderTicks without casting:
      
        Var<SliderTicks<Double>> ticks = Var.of(SliderTicks.classTyped(Double.class), SliderTicks.of(Double.class));
        
      Type Parameters:
      N - The number type of the slider.
      Parameters:
      numberType - The number type N in the returned Class<SliderTicks<N>>.
      Returns:
      The SliderTicks.class, typed as Class<SliderTicks<N>>.
      Throws:
      NullPointerException - If numberType is null.
    • numberType

      public Class<N> numberType()
      Returns the type of the value of the slider, which is also the type of every spacing and label position.
      Returns:
      The number type of the slider.
    • withMajorSpacing

      public SliderTicks<N> withMajorSpacing(N spacing)
      Returns a copy with major tick marks at the given spacing, counted from the minimum of the slider. A spacing of 10 on a slider running from 0 to 100 puts a major tick mark at 0, 10, 20 and so on up to 100. The major spacing is also how far the knob moves when the user clicks into the track beside it, or presses page up or page down, unless there are minor tick marks, whose spacing is used instead.

      A spacing of zero removes the tick marks, and with them the labels at the major tick marks.

      Parameters:
      spacing - The distance between two neighbouring major tick marks, in the numbers of the slider.
      Returns:
      A new SliderTicks with the given major spacing.
      Throws:
      NullPointerException - If spacing is null.
      IllegalArgumentException - If spacing is negative, not a number or infinite.
    • majorSpacing

      public Optional<N> majorSpacing()
      Returns the distance between two neighbouring major tick marks, if there are tick marks.
      Returns:
      The major spacing, or an empty Optional if there are no tick marks.
    • withMinorTicksBetween

      public SliderTicks<N> withMinorTicksBetween(int count)
      Returns a copy with the given number of minor tick marks between each pair of neighbouring major tick marks. Four minor tick marks between major tick marks which are 25 apart divide that distance into five equal parts, so a minor tick mark sits at every multiple of 5. Zero means that there are no minor tick marks.

      Counting the tick marks between the major ones, instead of declaring a second spacing, makes it impossible to declare minor tick marks which miss the major ones. On a slider for whole numbers the major spacing must still be divisible into that many equal whole number parts: a major spacing of 25 with 3 minor tick marks between them would need a minor tick mark every 6.25, so SwingTree logs a warning and draws no minor tick marks.

      Parameters:
      count - The number of minor tick marks between two neighbouring major tick marks.
      Returns:
      A new SliderTicks with the given number of minor tick marks.
      Throws:
      IllegalArgumentException - If count is negative.
    • minorTicksBetween

      public int minorTicksBetween()
      Returns how many minor tick marks sit between two neighbouring major tick marks.
      Returns:
      The number of minor tick marks between two neighbouring major tick marks.
    • withTickMarksVisible

      public SliderTicks<N> withTickMarksVisible(boolean visible)
      Returns a copy whose tick marks are drawn or not drawn, depending on the given flag. Tick marks are drawn by default.

      Tick marks which are not drawn still exist: the labels at the major tick marks are still shown, and the knob still snaps to them if withSnapToTicks(boolean) says so. This is how you build a slider with labels at 0, 25, 50, 75 and 100 but without any marks on its track.

      Parameters:
      visible - true to draw the tick marks, false to only use their positions.
      Returns:
      A new SliderTicks with the given visibility of its tick marks.
    • hasVisibleTickMarks

      public boolean hasVisibleTickMarks()
      Tells whether the tick marks are drawn, or whether only their positions are used.
      Returns:
      true if the tick marks are drawn, false if only their positions are used.
    • withSnapToTicks

      public SliderTicks<N> withSnapToTicks(boolean snap)
      Returns a copy whose tick marks the knob snaps to when the user moves it, or not, depending on the given flag. The knob snaps to the minor tick marks if there are any, and to the major tick marks otherwise. Without a major spacing there is nothing to snap to, and the flag has no effect.

      While the user drags the knob, the value of the slider is the number at the nearest tick mark, and when the user lets go of the knob, it moves onto that tick mark. An arrow key moves the knob to the next tick mark in the direction of the key.

      Snapping only ever applies to what the user does. When your application sets the value of the slider to a number between two tick marks, the knob sits between those tick marks, and the value is not changed behind your back.

      Parameters:
      snap - true to let the knob snap to the tick marks, false to let it move freely.
      Returns:
      A new SliderTicks with the given snapping behaviour.
    • isSnappingToTicks

      public boolean isSnappingToTicks()
      Tells whether the knob snaps to the tick marks when the user moves it.
      Returns:
      true if the knob snaps to the tick marks when the user moves it.
    • withLabelsAtMajorTicks

      public SliderTicks<N> withLabelsAtMajorTicks()
      Returns a copy with a label at every major tick mark, showing the number at that tick mark. All labels show their numbers with the same count of decimal places, namely the fewest which write every one of them exactly: labels at 0, 0.25, 0.5, 0.75 and 1 read "0.00", "0.25", "0.50", "0.75" and "1.00".

      The numbers are written independently of the locale of the machine, with a dot as decimal separator and without grouping, so "1234.5" reads the same everywhere. To write them the way a particular locale does, use withLabelLocale(Locale).

      The labels only exist while there is a major spacing, see withMajorSpacing(Number).

      Returns:
      A new SliderTicks with a number label at every major tick mark.
    • withLabelsAtMajorTicks

      public SliderTicks<N> withLabelsAtMajorTicks(Function<N,String> text)
      Returns a copy with a label at every major tick mark, whose text is computed from the number at that tick mark by the given function:
      
        SliderTicks.of(Integer.class).withMajorSpacing(25).withLabelsAtMajorTicks( v -> v + "%" )
        
      The function receives the exact number at the tick mark, computed as the minimum of the slider plus a whole multiple of the major spacing, so a slider from 0.0 with a major spacing of 0.1 hands 0.3 to the function, and never 0.30000000000000004.

      The labels only exist while there is a major spacing, see withMajorSpacing(Number).

      Parameters:
      text - The function computing the text of a label from the number at its tick mark.
      Returns:
      A new SliderTicks with a label at every major tick mark.
      Throws:
      NullPointerException - If text is null.
    • withoutLabelsAtMajorTicks

      public SliderTicks<N> withoutLabelsAtMajorTicks()
      Returns a copy without labels at the major tick marks. The labels placed at particular numbers through withLabelAt(Number, String) are kept.
      Returns:
      A new SliderTicks without labels at the major tick marks.
    • hasLabelsAtMajorTicks

      public boolean hasLabelsAtMajorTicks()
      Tells whether there is a label at every major tick mark.
      Returns:
      true if there is a label at every major tick mark.
    • majorTickLabelText

      public Optional<Function<N,String>> majorTickLabelText()
      Returns the function computing the text of the labels at the major tick marks, if one was supplied through withLabelsAtMajorTicks(Function).
      Returns:
      The label text function, or an empty Optional if the labels at the major tick marks show their numbers, or if there are no labels at the major tick marks.
    • withLabelLocale

      public SliderTicks<N> withLabelLocale(Locale locale)
      Returns a copy whose labels at the major tick marks write their numbers the way the given locale does. With Locale.GERMANY a label at 1234.5 reads "1.234,5", whereas with Locale.US it reads "1,234.5".

      The default is Locale.ROOT, which writes numbers independently of any locale: with a dot as decimal separator and without grouping, so the same label reads "1234.5". Pass Locale.getDefault() to follow the locale of the machine.

      The locale only affects labels showing numbers through withLabelsAtMajorTicks(). A text function passed to withLabelsAtMajorTicks(Function) does its own formatting.

      Parameters:
      locale - The locale whose conventions the number labels follow.
      Returns:
      A new SliderTicks with the given label locale.
      Throws:
      NullPointerException - If locale is null.
    • labelLocale

      public Locale labelLocale()
      Returns the locale whose conventions the number labels at the major tick marks follow.
      Returns:
      The label locale, which is Locale.ROOT unless withLabelLocale(Locale) says otherwise.
    • withLabelAt

      public SliderTicks<N> withLabelAt(N value, String text)
      Returns a copy with a text label at the given number, replacing any label which was at that number before. The number does not need to be at a tick mark:
      
        SliderTicks.of(Integer.class)
        .withLabelAt(0, "Cold")
        .withLabelAt(50, "Warm")
        .withLabelAt(100, "Hot")
        
      A label at a number outside the range of the slider is not shown. When a label at a particular number and a label at a major tick mark fall onto the same position, the label at the particular number is shown.
      Parameters:
      value - The number at which the label is shown.
      text - The text of the label.
      Returns:
      A new SliderTicks with the given label.
      Throws:
      NullPointerException - If value or text is null.
    • withLabelAt

      public SliderTicks<N> withLabelAt(N value, IconDeclaration icon)
      Returns a copy with an icon label at the given number, replacing any label which was at that number before. This is how a volume slider shows a muted speaker at its start and a loud speaker at its end:
      
        SliderTicks.of(Integer.class)
        .withLabelAt(0, Icons.MUTED)
        .withLabelAt(100, Icons.LOUD)
        
      A label at a number outside the range of the slider is not shown. When a label at a particular number and a label at a major tick mark fall onto the same position, the label at the particular number is shown.
      Parameters:
      value - The number at which the label is shown.
      icon - The icon of the label.
      Returns:
      A new SliderTicks with the given label.
      Throws:
      NullPointerException - If value or icon is null.
    • withoutLabelAt

      public SliderTicks<N> withoutLabelAt(N value)
      Returns a copy without the label at the given number, if there is one. The labels at the major tick marks are not affected.
      Parameters:
      value - The number of the label to remove.
      Returns:
      A new SliderTicks without a label at the given number.
      Throws:
      NullPointerException - If value is null.
    • labelPositions

      public sprouts.Tuple<N> labelPositions()
      Returns the numbers at which a label was placed through withLabelAt(Number, String) or withLabelAt(Number, IconDeclaration), in the order they were placed.
      Returns:
      The positions of the labels placed at particular numbers.
    • labelTextAt

      public Optional<String> labelTextAt(N value)
      Returns the text of the label placed at the given number, if it is a text label.
      Parameters:
      value - The number of the label.
      Returns:
      The text of the label at the given number, or an empty Optional if there is no label at that number, or if it is an icon label.
    • labelIconAt

      public Optional<IconDeclaration> labelIconAt(N value)
      Returns the icon of the label placed at the given number, if it is an icon label.
      Parameters:
      value - The number of the label.
      Returns:
      The icon of the label at the given number, or an empty Optional if there is no label at that number, or if it is a text label.
    • equals

      public boolean equals(@Nullable Object obj)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • toString

      public String toString()
      Overrides:
      toString in class Object