9

I want to use a FX8 Spinner control, but I want to bind the source to an IntegerProperty

int MIN = 0;
int MAX = 5000;
int STEP = 500;
IntegerProperty integerProperty = new SimpleIntegerProperty();

Spinner<Integer> spinner = new Spinner<>(MIN, MAX, STEP);

I understand the binding is set via binding to the valueProperty in the Value Factory. However this expects Property<Integer> and I cannot find a way to cast between IntegerProperty and Property<Integer>.

Obviously the below generates a compiler error:

spinner.getValueFactory().valueProperty().bindBidirectional(integerProperty);

Do I need to manually assign a change listener for both directions? Surely there is a neater solution using the valueProperty, this cannot have been an unforeseen situation.

SeeMoreGain
  • 1,263
  • 16
  • 36

2 Answers2

9

You can wrap an ObjectProperty:

ObjectProperty<Integer> objectProp = new SimpleObjectProperty<>(MIN);
IntegerProperty integerProperty = IntegerProperty.integerProperty(objectProp);

Spinner<Integer> spinner = new Spinner<>(MIN, MAX, STEP);

spinner.getValueFactory().valueProperty().bindBidirectional(objectProp);

IntegerProperty.integerProperty creates a property that's bidirectionally connected to the property it wraps.

VGR
  • 40,506
  • 4
  • 48
  • 63
  • 1
    thanks. I decided to go the other way and wrap the Spinner property and call `bindBiDirectional` from the `IntegerProperty` to bind 2 `IntegerProperty` objects (so I don't need to touch the model objects I am working with). – SeeMoreGain Mar 07 '16 at 04:43
  • 2
    @SeeMoreGain, please share the code snippet for your approach to solve the problem? – Buddha Sep 03 '16 at 19:41
  • Like @Buddha I was also interested in some code. However, now i'm using: `spinner.getValueFactory().valueProperty().bindBidirectional(integerProperty.asObject());`. Still had to redesign this code, because of a "premature garbage collection" problem, which kept the binding from working. [Following solution](https://stackoverflow.com/a/39438466/2642801) fixed it: 1. Declare an instance variable: `private ObjectProperty spinnerValue;`. 2. Initialize it: `spinnerValue = integerProperty.asObject();`. 3. Use it: `spinner.getValueFactory().valueProperty().bindBidirectional(spinnerValue);`. – SourceSeeker Nov 21 '18 at 21:18
  • This didn't work for me. It would compile but would throw a nullPointerException error at the spinner.getValueFactory...bindBidirectional line. However, when I reversed the binding and did it like this: **objectProp.bindBidirectional(spinner.getValueFactory().valueProperty());** it worked perfectly. – Michael Sims Feb 04 '20 at 15:10
  • @Buddha and others, we now have one answer in the answer itself and three more answers in the comments. My guess is that one of them is superior/universal and I should only take the time to understand (and use) that one. Can any of you say with confidence which one I should go for? I will give it a day or two and ask this as a new question if I don't hear back. – pateksan Dec 12 '20 at 01:31
0

Ok it is late but let me propose something else for the others. You can simply call the asObject() on your 'integerProperty'. That will send you back ObjectProperty value.

int MIN = 0;
int MAX = 5000;
int STEP = 500;
IntegerProperty integerProperty = new SimpleIntegerProperty();

Spinner<Integer> spinner = new Spinner<>(MIN, MAX, STEP);

spinner.getValueFactory().valueProperty().bindBidirectional(integerProperty.asObject());
Novy
  • 1,436
  • 1
  • 14
  • 26