spinner component

Jonathan Giles jonathan.giles at oracle.com
Sat Dec 17 02:11:23 PST 2011

A long time ago I mocked up a Spinner control to try and understand the 
API requirements. Unfortunately, right now I can't find the 
implementation (my machine is searching for it, but it's probably on 
another machine). In general, the approach I took was much the same as 
what you mention, although probably a slightly simpler approach (it 
wasn't fully implemented, so it is likely I hadn't hit all of the 
requirements yet). I thought I'd try to recall and outline the approach 
I took below (although I'll stick to keeping it high-level for now). I'm 
not saying it is a better or worse approach, I just wanted to offer a 
different point of view. Almost certainly I'll get much of the detail 
wrong, so sorry about that :-)

The approach I took was to have a SpinnerBase class that, I believe, had 
a callback property that would be called when the user incremented / 
decremented the spinner index. It was the job of this callback to return 
the value for the given index. An integer spinner may just return the 
provided index. A calendar spinner would perhaps take the given index to 
represent 'number of months since January, 1970', and return the 
calculated month String.

This SpinnerBase class would likely be abstract, with the 
implementations extending this and providing a default callback. You 
could obviously make the Spinner class be the most common spinner type 
(if one exists - maybe IntegerSpinner), and possibly consider having 
other spinners like CalendarSpinner, etc.

An alternative approach is that you could call what I refer to as 
'SpinnerBase' above 'Spinner' instead and give it a sane default 
callback (again, maybe integer), and also provide a library of pre-built 
callbacks for things like integers, floats (the API would require the 
developer to specify the amount to increment / decrement by), dates, 
etc. This is much the way the JavaFX team intends to move in future 
releases for things like cell factories, cell value factories, 
StringConverters, etc.

In essence, this approach is a one-method Callback<Integer, T> 'data 
provider', where the method is 'public T call(Integer index)'. It is a 
simpler data provider than what you mention. I guess my question is 
whether the additional API is required? Also, in my opinion, I think 
Integer, rather than BigInteger, is likely sufficient - but this isn't a 
major issue for me right now.

Anyway, let's keep this discussion going and see if we can end up at an 
agreement over the best approach.

Thanks for the proposal!
-- Jonathan

On 17/12/2011 6:16 p.m., Tom Eugelink wrote:
> I would like to propose the addition of a spinner control to OpenJFX.
> A spinner control for all means and purposes is a listview where only 
> one cell is visible (rendered) at a time. Moving to the next and 
> previous cell is done via clicking with the mouse on arrows or using 
> keyboard presses. The control's API could look like:
> Class: *Spinner<T> extends Control*
> T denotes the type it is holding; String, Integer, any bean.
> Properties:
> *- ObjectProperty<T> valueProperty()
> *  The value property holds the currently displayed (selected) value
> *
> - ObjectProperty<Boolean> cyclicProperty()
> *  Cyclic means that the spinners cycles back to the beginning when 
> the end of the list of values is reached, e.g. december -> next -> 
> januari, or vice versa (januari -> previous -> december).
> Methods:
> *- public void decrease()
> *  programatically select the previous value
> *
> - public void increase()
> *  programatically select the next value
> Events
> *- ObjectProperty<EventHandler<CycleEvent>> onCycleProperty()
> *  OnCycle method gets called when the spinners cycles (see cyclic 
> property).
> A value change event is not needed, since registering to the value 
> property will take care of that.  Detecting a cycle based on value 
> changes is cumbersome, so hence the OnCycle event.
> Implementation considerations:
> Since this actually is a list-with-just-one-cell, adopting a cell 
> factory may be a good idea.
> Even though a spinner is a list-with-just-one-cell, using a list as 
> its data source is restrictive, because lists always have a lower and 
> upper bound. For example, take a spinner that selects a year: the 
> value "year" has no natural lower and upper bound. It could have in 
> certain situations, but as a concept it has not. Therefor I would like 
> to propose the usage of a data provider, in this case a 
> single-value-linear-data-provider. Such a data provider uses a 
> BigInteger to represent the current value and can increment or decrement.
> Data provide API:
> - *public BigInteger getPreviousIdx(BigInteger idx);*
>   Calculate the previous index given the provided one, returning null 
> if there is no previous. (Spinner may cycle.)
> - *public BigInteger getNextIdx(BigInteger idx);*
>   Calculate the next index given the provided one, returning null if 
> there is no next. (Spinner may cycle.)
> - *public T getValue(BigInteger idx);*
>   Return the value for the specified index, could return null as a 
> valid value
> - *public BigInteger getIdx(T value);*
>   Return the idx for the specified value, returning null means the 
> value does not exist
> The DataProvider can be based on an actual list, or on an 
> implementation allowing the endless selection of a year.
> A initial (but fully working) implementation can be found at 
> http://code.google.com/p/jfxtras/source/browse/controls/src/main/java/jfxtras/scene/control/SpinnerX.java 
> (screenshot attached to the email).
> Tom

More information about the openjfx-dev mailing list