JDK-8098302 : Add Spinner Control
  • Type: Enhancement
  • Component: javafx
  • Sub-Component: controls
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2009-09-18
  • Updated: 2017-12-12
  • Resolved: 2014-08-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8u40Fixed
Related Reports
Blocks :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Sub Tasks
JDK-8098510 :  
JDK-8098511 :  
JDK-8098512 :  
JDK-8098513 :  
JDK-8098514 :  
JDK-8098515 :  
JDK-8098516 :  
Description
Add a spinner control to the toolkit.   See https://wiki.openjdk.java.net/pages/viewpage.action?pageId=15368236 for details.
Comments
Please enter a new JIRA requesting this feature. Thanks.
06-08-2014

Currently it looks like there's no CSS support to place the increment/decrement buttons inside the text field - a negative padding has some strange side effects. An additional CSS property which defines an offset value for the buttons would be appreciated.
06-08-2014

Thanks. I just added a link to that issue.
28-07-2014

Kevin, that is tracked via RT-37968.
28-07-2014

@Jonathan : last week you mentioned an issue with LocalDate and LocalTime factories relating to the inability to select sub-components (e.g., hours in a localdate spinner). Is this tracked in a separate JIRA? If not, then can you summarize the problem here.
28-07-2014

Changeset: http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/9e26a5eaed82 I'll leave this Jira issue open until I file Jira issues for remaining tasks. In the mean time these can be tracked at a very high level on the Spinner wiki page here: https://wiki.openjdk.java.net/display/OpenJFX/Spinner
12-07-2014

Regarding #1 -- yes, that was a typo. I fixed it. Thanks.
11-07-2014

Here is my feedback. Only #1 must be fixed before pushing the code (and no need for another patch). 1. You need to ensure that all new files have UNIX style "LF" (not DOS-style "CR-LF") line endings -- run "dos2unix" if you need to. Since your patch was attached as a plain text file and not a zip, I cannot tell whether it is correct. 2. I almost hesitate to ask...any plan to provide caspian styles for spinner (OK if this comes later) 3. Malformed html in your Spinner javadoc. For example: 160 * if this constructor is called, the only valid generic type for the 161 * Spinner instance is Integer, i.e. Spinner<Integer>. The ``<Integer>'' is not displayed by javadoc and should be ``&lt;Integer&gt;'' 4. Cut-and-paste error in the Spinner(double ...) constructor. It says that the only valid generic type is Integer, but should be Double (and same comment as above about the html). Ditto for the Date variants of the constructor. 5. In the following constructor: public Spinner(LocalDate min, LocalDate max, LocalDate initialValue, long amountToStepBy, TemporalUnit temporalUnit) the "@param temporalUnit" is missing. 6. The concrete subclasses of SpinnerValueFactory should specify the initial value of the converter property (I presume there is a default String <--> double converter). Also, for double did you decide how the double --> String formatting will be done? 7. Could use a description of the default values in the javadoc; e.g., what is the default amountToStepBy (1, I presume). 8. javadoc for LocalDateSpinnerValueFactory is incomplete Once this goes in please file JIRAs for follow-on work (fixing up javadoc, better icons, support for ScrollWheel, acceleration when holding down the mouse button, etc). +1 from me
11-07-2014

Kevin, I've still got holiday brain, but your point 1) above is back to front, isn't it? Dos line endings are CR-LF, and unix are LF, so I should be ensuring the line endings are LF, correct? I have a knack for getting these wrong, so I want to be sure. Regarding your other points: 2) Yes, caspian styling will come later. 3) Fixed. 4) Fixed. 5) Fixed. 6), 7), and 8) I'll work on next week!
11-07-2014

Despite my "hate of factories", the code looks good to me. Essentially, a spinner is a mix of "slider-like API (min/max/value)" and "list-like API (array of strings)". This can be generally factored out by subclassing and reimplementing methods or by configuring a helper object (for example, a factory) and forwarding to it when details are needed. Really, the job of a factory is to stamp out instances, so I'm not sure that the helper object is following the factory pattern. In any case, the work looks good and I'm not sure that a subclassing hierarchy (Spinner, NumericSpinner, ListSpinner) would be cleaner or more extensible. +1
03-07-2014

Attaching the final patch for review prior to inclusion in the 8u-dev repo. There is still plenty to be done on Spinner, so this is not the end!
30-06-2014

I'm pretty sure min and max will be used on all spinners, including LocalDate. I think the convenience constructors on Spinner itself should be for the most likely scenario's, so you are right that maybe for LocalDate specifying time unit is too precise. In the end all configurations are available on the factory classes and it is a fairly minor change from the convenience constructor to the Factory constructor.
27-06-2014

Attaching latest Spinner implementation code for anybody who is interested in testing and / or giving feedback on.
27-06-2014

After an internal API review of the Spinner API, I am now presenting a very-nearly-final API for initial pushing to the 8u-dev repo (for 8u40). This does not mean that the API is totally final - just near enough something we are happy with to go into the repo. The API doc is here: http://jonathangiles.net/javafx/spinner/v2/ Here are the changes (please read beneath this list for my concerns): * Added new constructors for other value factories to Spinner (e.g. constructors for LocalDate and Double) * Added amountToStepBy to the Spinner int value factory constructor * Removed the calculate* methods from SpinnerValueFactory - these can be added back in when demand is present (in a future release) * ListSpinnerValueFactory should have ObservableList, not list * Renamed IntSpinnerValueFactory to IntegerSpinnerValueFactory * Test that changing ListSpinnerValueFactory items list results in updated value in Spinner * I've added more unit tests - there are around 130 unit tests now, giving quite good coverage * Added set/get/property for min/max/items/etc API to ValueFactories * SpinnerValueFactory no longer extends StringConverter, it is now a property that can be set on a SpinnerValueFactory (and which by default is non-null with a mostly-sane implementation). This also allows for users to configure how to render doubles. * LocalDateSpinnerValueFactory now has min/max properties My concerns: * One piece of advice in the API review was that the constructors in Spinner have all parameters that match the most complete constructor for each SpinnerValueFactory. This means that Spinner(min, max, initialValue) has changed to Spinner(min, max, initialValue, amountToStepBy), for example (and it's even worse for the LocalDate Spinner constructor: Spinner(min, max, initialValue, amountToStepBy, temporalUnit)). My concern is that these constructors are more complex than what most people would want - e.g. I imagine most people using the int spinner would want to step by one, but they are forced to state that. Similarly, LocalDate users probably want to step by a single day, but they have to work out what amountToStepBy and TemporalUnit they need to specify (which is a trick question, as they actually want to specify ChronoUnits.DAYS). I would be inclined to provide constructors that do not take every possible argument, to instead cover the more common cases. * To have API consistency I've done something weird with the LocalDateSpinnerValueFactory - I've added another constructor whose first two arguments are min and max, despite the fact that min/max do not appear in other constructors in LocalDateSpinnerValueFactory. I did this for consistency across the other SpinnerValueFactories, but I'm keen to hear peoples thoughts. The alternative is to place these two arguments at the end of the argument list, or to change the constructors to have min/max be more prominent in earlier constructors of LocalDateSpinnerValueFactory (the reason why I've not done this is that it doesn't feel likely that min/max will be used, but I might be wrong here). * We have a LocalDateSpinnerValueFactory, but I'm now wondering whether we should have a LocalTime equivalent, or whether we just make LocalDateSpinnerValueFactory more general by having a LocalDateTimeSpinnerValueFactory. Finally, there is still work to be done before this goes final, which is being tracked here: https://wiki.openjdk.java.net/display/OpenJFX/Spinner
27-06-2014

Rather than upload zip files of the Spinner JavaDoc for people to download, unzip, review, and then have litter their hard drives for the rest of eternity, I have uploaded the latest javadoc here: http://jonathangiles.net/javafx/spinner/v1 One thing I'm curious about is if anyone has suggestions for additional value factories that should be included with JavaFX? Presently I have implemented integer, double, List, and LocalDate value factories. Does anything stand out as being particularly useful for people (or is there particular functionality that these value factories should have)?
27-06-2014

BigInteger and BigDecimal? For unlimited spinning?
24-06-2014

I've locally changed the code as in 3) in one of my earlier comments. Now wrapAround is a property of SpinnerValueFactory, rather than Spinner, and SpinnerValueFactory no longer has a reference back to Spinner.
13-06-2014

I added a todo list for Spinner here: https://wiki.openjdk.java.net/display/OpenJFX/Spinner
10-06-2014

@Eric: Thanks - I have annotated the constructors of Spinner and the SpinnerValueFactory implementations with @NamedArg annotations.
04-06-2014

SpinnerValueFactory subclasses could be made FXML-friendly by annotating their constructors with @NamedArg. For example, we could write: <?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.layout.*?> <?import java.lang.*?> <?import spinner.*?> <StackPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> <children> <Spinner> <valueFactory> <SpinnerValueFactory.IntSpinnerValueFactory min="10" max="20"/> </valueFactory> </Spinner> </children> </StackPane>
04-06-2014

I compiled the Spinner prototype and drop it in Scene Builder 2.0 library. See attached snapshot (spinner-in-sb.png).
04-06-2014

I'm attaching a first pass at javadoc for the Spinner control. Note that many of the links don't work as the javadoc tool could not resolve links to JavaFX API. I do have a few areas where API feedback is particularly welcome: 1) What is the API preference for specifying min/max/initialValue in the Integer and Double value factories: is it min/max/initialValue or min/initialValue/max. Personally I prefer the latter approach, but the current code uses the first approach. 2) Currently the value factories have toString(T obj) and fromString(String str) methods that do not do any validation that the value being converted is valid (i.e. within range). For example, if the min / max values of an integer value factory are 0 and 10, what should we do if we call toString(100) or fromString("100"). In my opinion we just let the conversion happen, as we deal with validity checking later in the process anyway. 3) I'm wondering whether the wrapAround property, currently on Spinner, should move to the SpinnerValueFactory. It feels more at home there, and it would also mean that the SpinnerValueFactory no longer needs to have a reference back to the Spinner. If we do this, perhaps a more generic name for SpinnerValueFactory should be used, in case we ever want to use it elsewhere in the future. 4) I still need to add API to specify the DecimalFormat in the Double value factory, but I was wondering if anyone had any additional API that was considered useful.
03-06-2014

I'm allowed to be pragmatic! :-) In this case, the value factory approach used in my prototype is very much in line with our general callback approach used in other controls (cell factories, cell value factories, page factories, day cell factories, etc), even if it isn't list-based like our other controls. It is also the far more comfortable approach (for me, anyway), compared to having an int-based list as the backing model (which to me feels very constraining). If this is a big issue then we can rollback the intent of the Spinner control to just being list-based, but I think that is a backward step. Similarly, the style class approach to me seems like the most pragmatic approach, based on what I said above. The alternative, that we've both discussed, ties us into an Orientation/HPos world view (although in reality I think it would require custom enums - I see you use ArrowPosition and ArrowDirection enums). The biggest problem with this approach is the requirement to style from an external css file, or use setStyle, which, as far as I understand, is the slowest path in the css engine as it needs to parse at runtime. This means that the approach required for people who are using multiple Spinners in their application is to either call setStyle on each of them as necessary, or to specify unique style classes on each Spinner, so that they then may be styled via CSS using the -fxx properties you mention. This seems a long way round, compared to setting the style class based on one of the predefined strings as in my prototype. In any case, either approach at specifying the style is largely fine and it is still up for discussion. Like I said it is somewhat uncharted territory, and we can continue to refine as we move along. Spinner is still in the very early prototype stages, and I've only taken it this far to discuss the implementation and API concepts. If the most contentious issue currently is how to specify the styling, I feel like I must be doing something right! :-)
03-06-2014

Strongly separating functional API from UI is something I try to do with my controls. If it is not clearly part of the control, then it belongs in the skin and should not expose through the control. I think you maybe should take an tiny peek into what I've done with ListSpinner. Here the skin uses styleable properties like -fxx-arrow-direction and -fxx-arrow-position. https://github.com/JFXtras/jfxtras/blob/8.0/jfxtras-controls/src/main/java/jfxtras/internal/scene/control/skin/ListSpinnerSkin.java This makes using it much more natural IMHO; they are separate properties, as I would expect them to be, they're just set through CSS because it's UI. CSS is a first class citizen, so it should be used as such. And they are easily settable through a Java API by using setStyle, not unlike using a class, as it is done in the sample code. https://github.com/JFXtras/jfxtras-labs-samples/blob/8.0/src/main/java/jfxtras/samples/controls/ListSpinnerSample1.java Of course it is some what contradicting to introduce a new type of data providing for a control (swing model alike, instead of a list) and then start using "traditional way of doing things" as arguments why something is implemented a certain way ;-) Anywho, I made my point, it's your implementation.
03-06-2014

Attaching updated sample code. The main changes are the introduction of the two new style classes I spoke about earlier (horizontal buttons on left and right), and unit tests - there are about 40 that cover the basic situations. More can come (especially related to the separate value factories - I've only done a few small int spinner tests so far). I think now is a really good time to get this API reviewed more comprehensively, so I will be pushing to do that in the coming days.
03-06-2014

Here's the relevant documentation and some brief thoughts regarding accessibility on Windows and Mac. ============================= Windows: http://msdn.microsoft.com/en-us/library/windows/desktop/ee671645%28v=vs.85%29.aspx UIA_SpinnerControlTypeId : 50016 It looks like on Windows the Spinner can be implemented using either the IRangeValueProvider or the ISelectionProvider control pattern. I think using the ISelectionProvider approach sounds better, as the IRangeValueProvider approach brings with it the need for integer indexing, stepping, and knowing min / max values (which might not always be available). It looks like either way we go, we will also be sure to implement the IValueProvider interface. I looked at a few native uses of spinner (the Layout tab on the command prompt properties window, and in the ribbon area of Microsoft Word for left indent), and in both cases it seems that neither IRangeValueProvider or ISelectionProvider are implemented. In the MS Office case, the Spinner has as children an edit box and two buttons. In the (presumably) older command prompt properties window, the buttons are children, but the edit field is not a child of the Spinner. ============================= Mac: https://developer.apple.com/library/mac/documentation/UserExperience/Reference/Accessibility_RoleAttribute_Ref/Role.html#//apple_ref/doc/uid/TP40007870-Roles-AXIncrementor AXIncrementor It took a bit of hunting, but I found an example of AXIncrementor in the XCode properties window, on the 'Text Editing' tab. The AXIncrementor has two actions (AXIncrement and AXDecrement), and two relevant attributes (AXIncrementButton and AXDecrementButton). It does not look like the AXIncrementor has any relationship to the AXTextField beside it.
03-06-2014

Tom, thanks for the discussion. I agree that it would be nice to have a flexible means of specifying the visuals, although oddly we're veering into territory that is not frequently entered for JavaFX UI controls. In terms of precedent, I can think of the following cases: * TabPane has two visuals: normal and 'floating'. Floating is specified by calling tabPane.getStyleClass().add(TabPane.STYLE_CLASS_FLOATING). * Pagination has normal buttons, or 'bullet' buttons. Again, this is specified via a STYLE_CLASS_BULLET styleclass that can be set on the Pagination instance * ColorPicker is the same, with normal, 'button' and 'split button', specified with STYLE_CLASS_BUTTON and STYLE_CLASS_SPLIT_BUTTON. This is why I've currently gone with the approach in Spinner, where we just have different style classes to specify the different options. An alternative (although largely synonymous) approach would be to introduce an enum, but that feels like it costs more without any particular gain (that is, it is equal for me to add additional style class strings and enums, but the style class strings are cheaper). Regarding supporting touch devices - we'll do it with Spinner the same way we do with other controls - specialised code in the skin. The framework just adapts as necessary. I'm not quite following your last comment. With the style class approach, it is public API - developers can call getStyleClass().add(....) and specify the style class they want (which will then be styled via CSS and the skin code). When using styleable properties on the skin, there is no public API (in Java), and the only way the properties are exposed (and able to be set) is via external CSS files (unless you're also exposing the properties from the skin via the control, but I don't think that is what you're doing or proposing). The only other option I can think of (which is limiting for other reasons) is to have two properties: * Orientation arrowOrientation: Used to specify whether the arrows should be vertical or horizontal * HPos arrowHPos: Used to specify whether arrows should be set on the left, right, or centered. The downside of this approach is that it of course ties us into a certain way of thinking. My gut feeling right now is that the current style class approach is the best option we have - it follows precedent, it is flexible (we can add new styleclasses, but we should be restrained - we don't want 24 as you say), and is public API. The only other consideration is whether we also add in horizontal-left and horizontal-right style classes. I can't see any issue with that, and if we include these I believe we are hitting the bulk of the use cases and probably the majority of the styles most people expect.
02-06-2014

I find it strange that given two configurables (direction and location) the implementation ends up with CSS classes representing combinations. What if there happened to be a third configurable with four possible values, that would result in 24 possible combinations. Some normalization seems to be in order here. Also I think the UX spec is more a functional requirement, but not an architectural / implementation specification. So the fact that the UX shows four settings does IMHO not mean there should be only four, it means there should be at least four. I always work from the assumption that I do not know in advance what all possible use cases are. So I try to keep my implementations as flexible as possible; I have no idea how sensible arrows at the top and bottom will be, but horizontal arrows at the bottom do not seem far fetched. I indeed have chosen for styleable properties on the skin, since I do not want to leak UI aspects into the control. On a touch device a spinner control could very well be represented by drums (similar to the date selector in iOS) and have no arrows at all. Step size would then be determined by swipe speed or distance instead of press duration. But I'm not certain how the JavaFX team intends to support touch devices. Do coders need to use different controls on touch devices or does the framework automatically adapt? About that the style can only be changed via CSS when using stylable properties on the skin; isn't that the case now as well, using the style classes?
30-05-2014

Attaching updated prototype. The main thing to discuss in this update is the addition of two new methods on SpinnerValueFactory: public int calculateStepAmount(int stepCount, double pressDuration) public long calculateStepDuration(int stepCount, double pressDuration) These methods allow for the increment / decrement values to be dynamically determined based on the number of iterations and the duration since the mouse was first pressed down. This allows for the Spinner to 'speed up' after it has been held down for a suitable time. Initially I thought I would just implement this internally with no API, but the result wasn't pleasing - the duration would get too fast and the steps too great (which was exacerbated by the int spinner only having values between 5 and 10). The default implementation of both of these methods is to not speed up, but my thinking is to add smarter implementations in the pre-built subclasses that can take into account their range. The one thing I don't like is how the code is likely to be very similar in implementing both methods. I could return a Pair, but that just feels bad. I'm open to suggestions though...
29-05-2014

@Tom: In fact, the way I currently support changing the style is simply by adding / removing public static final style class strings from the spinner styleClass list. There are three (STYLE_CLASS_ARROWS_ON_LEFT, STYLE_CLASS_SPLIT_ARROWS_VERTICAL, and STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL). The fourth, default style is used whenever there is no other applicable styleclass set. There is some precedent in controls for having the skin draw in a particular way based on the presence of a style class in the control. The alternative approaches would be to either: 1) Introduce a styleable property and possibly an enum on the Control. This would therefore become public API. The downside of this approach is that we're creating more public API. 2) Introduce a styleable property on the Skin. This would probably just rely on String comparisons, and wouldn't be public API. The downside of this approach is that we've lost the ability to change the Spinner style in any way other than via external CSS. This is why my current thinking is to use the styleclass approach. In terms of style options, I chose the four combinations (right, left, split vertical, split horizontal), as these are what we have specified in the Spinner UX documentation here: https://wiki.openjdk.java.net/pages/viewpage.action?pageId=15368236 I am open to adding additional styles (i.e. horizontal buttons on the left or right, rather than the horizontal split we have now), but I'd have to see if there is demand. Yes, alignment of the text can be set on the TextField. The current implementation uses a TextField in both the editable and non-editable cases (the editability of the TextField simply toggles as appropriate). This allows for easier copy/paste interactions too. @Ladislav: Yes, the design is still just using placeholder graphics. They will be refined significantly by the time the control is finished.
29-05-2014

I think you made setting the position configurable by CSS. This is important because for example JFXtras CalendarPicker uses embedded Spinners and the user must configure the spinner through CSS then. But I'm unfamiliar with the implementation you used (not StyleableProperty). Does this work if the CSS is set both as a class and through the setStyle? In JFXtras ListSpinner I created two styleable properties: -fxx-arrow-location (left, right, split) and -fxx-arrow-direction (horizontal, vertical), allowing for 6 combinations. I have the impression you only have 3 combinations, is that just for demo? http://tbeernot.wordpress.com/2013/08/22/using-css-in-javafx-to-keep-the-api-clean/ Also I have a value alignment property for position the string through CSS. Are you considering doing this by CSS on the text-field? ListSpinner alternates between using a label (non editable mode) and a text field (editable). https://github.com/JFXtras/jfxtras/blob/8.0/jfxtras-controls/src/main/java/jfxtras/internal/scene/control/skin/ListSpinnerSkin.java (BTW: eclipse has problems compiling the switch inside the lambda, interesting...)
29-05-2014

Very good work. Jonathan it's cool. API is designed very well. My notes (about design): 1. In Default placement of increment/decrement buttons (right), arrows have no equal to the position (different 1px), in (other placement I don't know) 2. In Default placement of increment/decrement buttons (right) or left corners on left or right side of textfield no equal as corners increment/decrement buttons 3. For all placement of increment / decrement buttons (right, left, split vertically, split horizontally), center arrows in buttons (horizontally, vertically) 4. Spinner keep spinning: could be slower at first and then more rapidly (MS Windows I think it has done so...)
29-05-2014

Attaching updated HelloSpinner.java and spinner.css files. The API is relatively unchanged, this change is more about fleshing out the skin and behavior code. There is one sizing bug that needs to be resolved, but generally things work. Changes include: 1) Improved skin / behavior code. The Spinner now supports different placement of increment / decrement buttons (right, left, split vertically, split horizontally). 2) You can hold down the buttons to have the spinner keep spinning. 3) RTL support (although, to be fair, it came for free - HelloSpinner now just has a toggle to test it). 4) Improved keyboard navigation. One concern Steve mentioned to me offline was what the precedent was for having a model that was required in controls API, especially in relation to having to 'reach through' to it to configure settings. My thinking on this is that it is quite uncommon, but there are two options we have if this doesn't seem right (to me it seems ok as it is, and personally I wouldn't do anything more): 1) We could introduce a specialised IntegerSpinner class that makes setting the min, max, initial value, step amount, etc more direct. 2) We just make sure the javadocs are super clear on how to achieve this. The advice would be that, if you want a general integer spinner, just call the Spinner(min, max, initialValue) constructor. If you want to customise (and at present there isn't much more to customise), you can either create a new IntegerSpinnerValueFactory and set the properties there, before setting it on the Spinner, or alternatively you can get the valueFactory from the Spinner, cast it to an IntegerSpinnerValueFactory, and make the changes directly on that model. Anyway, now is a good time for people to test and offer their thoughts on the API. I'm fairly close to locking something down, so I'll be taking this discussion wider soon (in other words, now is a good time for the watchers in this issue to influence the API before there are more voices added to the mix!).
29-05-2014

I spent a bit of time tweaking visuals (although we're still a long way from being finished visually). I've also started to split the skin and behavior code out properly. To run this code now requires you to download and place the spinner.css in the same package as HelloSpinner.
27-05-2014

I was mixing a little with combobox, listview and the hopefully upcoming checkedcombo/list. I do not want a spinner to multi select.. I prefer the lambda because it's an easy one-line constructor and hits a sweet spot of use cases IMO. And can't you just extend ListSpinnerValueFactory and override toString/fromString to get the StringConverter functionality?
27-05-2014

Fixing small error in the LocalDateSpinnerValueFactory code.
27-05-2014

I'm attaching an updated HelloSpinner for API review (although don't look too closely at the implementation, you may go blind). This API is moving closer to a 'proper' implementation - JavaFX properties are being introduced. The big change is how I've redefined the value property to be a final property of SpinnerValueFactory. This has implications for setValue and getValue, which can no longer be overridden. Despite this, I had no trouble changing to use the more JavaFX-esque approach of adding listeners and retroactively correcting incorrect values (rather than intercepting before in the setValue method). This code also introduces a number of small tweaks: * Support for variable amounts of stepping (at the moment only settable via the Slider in the test application). * The addition of a double spinner value factory. * Tweaks to the Spinner API (increment / decrement no longer return values, etc). * Support for setting the step increment (it was always in the calendar value factory, but I added it to the int and double spinner value factories)
27-05-2014

There is not quite enough API in the integer constructor to be useful. You can't set the increment. Of course this argument (and any others) could be added. What is the precedent here?
27-05-2014

@Tom: I don't think we will want to consider any additional changes to the existing controls, in light of the approach we take with Spinner. Regarding stripping out a simpler SelectionModel - it's possible, but I would be dubious of what it would achieve (and whether we can do it in a backwards compatible way). The issue is particularly that, of course, all selection models at present are index-based, so we would need to override all functionality of the extracted object-based model. I guess my feeling is that it is of little benefit for a lot of potential pain (and the benefit is mitigated by the duplication of API that does the same thing). @Mikael: You say "select one or many". To be clear, I don't think you're proposing that the Spinner should allow some weird multiple selection, correct? Regarding separating out the string conversion from the value factory (or, adding a separate string converter that can be set on the Spinner to override the value factory 'default implementation') - I think that is a fair idea. One question is whether to use the existing StringConverter API (with toString and fromString methods), or to use your Function / lambda approach. I have a feeling that whilst your approach is definitely prettier, having support for StringConverter would be useful for both converting to strings and reading back the input into the textfield into an object of the appropriate type. I'd need to explore further, but I'm open to suggestions. @Steve: Good suggestions. I might explore adding floating point and hexidecimal spinner value factories. I'd need to chat more (or be convinced further) about page increment / decrement. My latest Spinner prototype already supports editing / read-only modes. When an invalid value is entered, it is up to the value factory to respond, but in my current code it simply returns the value back to a valid value. With the 'default factory should be an integer spinner', that is essentially true if developers instantiate the Spinner with the (int min, int max, int initialValue) constructor. Similarly, a List Spinner is available with the Spinner(List<T> items) constructor. I don't believe there is a direct precedent, but for example, ListView allows users to pass in an List of items, or call the default constructor and have a default list created. One other area I'm working on is to overload the increment / decrement methods, with versions that take a 'steps' argument, indicating the number of steps to increment / decrement. The original methods therefore just call increment / decrement with a steps value of 1. Thanks for the feedback. I'll try to post an updated prototype today, if time permits.
26-05-2014

Hi Jonathan, Looks really good. Background: A Spinner is not a combo box even though the two controls are similar in many ways. Normally, spinners are used to increment and decrement numeric values. Usually, these are numbers but sometimes they are dates. Very rarely, a spinner is used to show non-numeric values. If number are displayed, then they are usually integers, but I have seen floating point and hexadecimals being used. A spinner will have a minimum, maximum, increment, decrement and on some platforms, have a page increment and decrement. Sometimes spinners can wrap. Also, spinners can be editable or read only. I like the approach and I see that most of these features are addressed in your prototype code. The minimum and maximum, increment and decrement are part of the model. The setValue() method (although not hooked up) allows random access to the stream of values. For example, you wouldn't want to have to increment 1000 times to get to a place in the spinner. There are standard factories to handle common cases (could consider adding factories for the other cases I have identified). The issue of read only versus editable needs to be sorted out. If a spinner is editable, what happens when the wrong thing is typed? It might be nice if the default factory was an integer spinner and there was API to set the maximum, minimum and increments but this can be discussed. Is it reasonable to force people to create a factory for the simplest and most common case? Is there precedent for this in FX? If it makes sense to you, I suggest that you continue with this prototype and touch on some of the areas I talked about above. Steve
26-05-2014

Also be crystal clear on how null values are handled. Especially for combos I use null to denote "<None>" as in no value is selected. This is so I don't have to use an extra checkbox to select that I want to select something.
26-05-2014

My very quick 2 cents. A very common use case for me for spinners, combo boxes, lists and similar is that I have a number of objects and want to show them and select one or many. The only thing is that these objects doesn't .toString() to the string that I want to show to the user. I therefore think a constructor where you can do this would ease usability for the vast number of spinner cases. I understand this can be done with the factory but that's to hard to do for this very common use case IMO. Spinner(List<E> items, Function<E, String> toString) {..} With lambdas this would be super easy to use to select by using name. new Spinner(persons, Person::getName) Btw, I also think this should be done on ComboBox, ChoiceBox and ListView And it should be clear from the JavaDoc that the list is overtaken and any changes to it after the constructor will lead to all hell breaking loose. Or you should make a defensive copy and specify that. The ListSpinnerValueFactory that handles this should just fromString() on what the function returns.
26-05-2014

I think the proposed implementation is a good one, the discussion should be about how much uniformity should be added to it. And maybe a short consideration on how you are going to add infinite data sets to the other controls in v9? I understand the agile one-control-at-a-time approach, but by now you should have enough mileage under your belt to maybe look forward a bit and think about enhancing the controls. Some uniformity is a great good. After having chosen an implementation I always like to step back and consider the consequences. Using the explicit methods is much better. Do you want an abstract class or would an interface be better here? (Personally, I often use abstract classes.) Considering the selectionModel; how about my suggestion on splitting the current selection model into two? A SelectionModel and SelectionModelWhatItShouldHaveBeen (or whatever better name we can come up with); the latter holding the object based methods, the first extending that and adding the integer based methods. Spinner could then implement SelectionModelWhatItShouldHaveBeen. This would maintain some form of uniformity. Do note that my version of spinner (ListSpinner in JFXtras) also does not implement SelectionModel. Basically registering to the value property suffices. This also can be a long term decision (not supporting SelectionModel). Is there a need for it?
26-05-2014

Attaching an alternative implementation of HelloSpinner where I remove the SpinnerRequest and SpinnerAction classes, instead adding increment, decrement, getValue and setValue methods to the SpinnerValueFactory class. This is cleaner than the earlier approach based on the SpinnerAction enum.
26-05-2014

Thanks Tom for your feedback (and for discussing Spinner ideas with me before I did my experiment). I'm glad you put the word 'all' in inverted commas, as there is some degree of precedent for what I've done in Spinner. For example, Pagination has the pageFactory, and TableColumn / TreeTableColumn have cellValueFactory. These are both callback APIs where something is returned on-demand, rather than being pre-calculated in advance (or wrapped in a dynamic List). I appreciate that ListView, TableView, ComboBox, etc all have the List approach, but that is because that is what feels best for them. The Spinner approach I've taken initially is because that is what feels best for a Spinner, to me. Also, yes, the Spinner class has a constructor for (int min, int max, int initialValue) and (List<T> items), so the simplest and most common cases could conceivably be handled without any knowledge of the underlying model, if people weren't interested. I'm glad you mentioned SelectionModel - I forgot to in my original comment (although I alluded to my concern, which as we both note is the limitations of integer indexing a Spinner, when many data models just don't really make sense with an integer index). My thinking is, again, slightly controversial, but I'm keen to discuss it: is the right thing for a Spinner to just not use the SelectionModel API? This breaks in tradition, but it seems that a Spinner has a value and conceivably an infinite number of values (partly because the spinner value factory could keep on going, but also because the user could type in input). I wonder how frequently the ability to plug in a different selection model is necessary in general, but specifically for a Spinner I wonder if it would ever be used. If not, we could stick with just the current API of increment, decrement and set/get/value(Property). Regarding your usability comment, I totally agree, and I would implement it the way you are saying - with the step speed increasing as the duration of the mouse press increases. This would require some more API to enable stepping more than one step at a time. Finally, I should note, that the current API approach is to use a SpinnerRequest callback parameter. An alternative approach is to introduce separate methods for increment, decrement, setting a value, initialising a value factory, etc. At this point I consider this topic to be largely irrelevant as we can easily switch to the Chosen Approach. The bigger question is whether we take a value factory approach, or a List approach.
25-05-2014

It is great to see you have taken many of my concerns into consideration, and it is good to have a control that is capable of an infinite data set; that will probably come in handy for someone some time. One concern is not addressed; given than 'all' the other controls like ComboBox and TableView all are list based in their API, I feel this example is deviating from the expected API too much. This implementation is leaning towards Swing's model approach, and models is one of the main reasons why Swing has such a steep learning curve. JavaFX has chosen to be more easily accessible and providing controls simply with a list of things to render is one of the biggest steps. You already mentioned that Spinner functionally is very similar to ComboBox; therefore IMHO a user will expect a Spinner to have a constructor where he can provide a list, a setItems method and the standard selectionModel. This is the way things are done in JavaFX and keeping things uniform is very important for the feel of quality. This however will also introduce the problem that selectionModel is integer based (it should never have been, but that is beside the point) and thus will spark the debate how important uniformity is; a value discussion with no clear winner. I'm not sure what the best solution is to marry both models. One could support selectionModel until you can't (e.g. throw an exception in the factory once an integer can not longer be associated to a value), at which point the user must use the underlying infinite API and not the integer based one. For the extreme majority of the use cases this should not be a problem, after all how often do you spin a year beyond 2^31, only things like BigIntegerSpinnerFactory will have values that will cause problems. It will make writing a factory a lot more complex if you have to project an integer to the dataset. Will that be a cost acceptable for maintaining uniformity. Or maybe we can split selectionModel into one without the integer part? Finally one usability improvement; should there be a way to have the control speed up spinning? I suppose holding the up or down arrow will start to step automatically, maybe the step speed and then size can be increased when the button is held longer. First steps of 1 which 300ms in between, slowly decreasing to maybe 50ms and then increasing the steps to size of 10, 100, ... Not sure what a good feel would be. It could depend on the dataset so maybe the factory should play a role here.
25-05-2014

I thought I would spend a bit of time exploring the Spinner API domain. I'm attaching the outcome of that exploration - it is one possible way a JavaFX Spinner control could go. I should note that this code is the result of about an hour hacking - it takes almost every shortcut and will need a bit of effort to make it pleasing both visually and API-wise. In any case, I wanted to explore an API that was not List-based. This may seem odd or controversial given a Spinner is essentially a ComboBox with a different set of visuals, but I like to think of the Spinner as an infinite (or wrappable) list, whereas I like to think of a ComboBox list as well-defined and finite. The approach I have taken is to use a callback API that handles the increment and decrement operations. This makes the Spinner control a very simple API - it forwards all requests down to the model. This sample supports wrap-around (e.g. December -> January), editing, and string conversion back to the model. An alternative approach is to be List-based, but I feel that this brings with it some degree of complexity in relation to the simpler use cases (e.g. integer stepping, calendar stepping, etc). Developers would be forced to provide an AbstractList (or similar), and do the work to determine the size() and get(int) methods, and this would force them to also work using integer indexing, which may or may not be applicable to their domain (e.g. how do you represent a milliseconds since the epoch spinner when you only have ints?!). The attached sample application supports Integer, List and LocalDate (i.e. the new Java 8 date / time API) as a proof of concept. I really do look forward to feedback on the API.
24-05-2014

Spinner control does not yet exist in JavaFX, and this issue is the most highly voted Jira issue related to Spinner. I have therefore repurposed this Jira issue to be forward-looking towards adding Spinner in a future release (perhaps as soon as 8u40, but for now targeted at 9).
01-05-2014

Not in PRD, dropping from release.
16-04-2013

Dev team may want to refer to the following Eclipse bug to avoid issues they have encountered related to Spinner and other widgets: https://bugs.eclipse.org/bugs/show_bug.cgi?id=29779
12-10-2012

G11N/OK
12-10-2012

The linked a360 has no mention of the spinner control. Do you mean Number Stepper? If so - SQE is OK with it
12-10-2012

Docs/OK
03-10-2012

Implements A360 Feature http://oracleplan.oracle.com/goto?ra_=entity&entityType=FEATURE&entityId=713788
12-09-2012

This Preview component did not make the SoMa feature freeze. We will schedule it for a future release.
24-02-2010