问题
I am trying to practice my binding. I want to make a window with two spinners and just get them to show the same value.
The problem is that the binding is unreliable: the spinners seem to stop updating each other if they are clicked too fast. Both spinners still respond to clicking, and clicks are counted correctly on the spinner being clicked, but the other spinner stops updating and never recovers. And it doesn’t have to be very fast clicking at all to cause it.
My code is based on this answer (currently scoring 8) showing how to bind a spinner to an IntegerProperty. That answer is enough to produce the behaviour I am struggling with, but I followed the brief discussion that ensued under that answer. It has other options shown and resources linked, including a hint to use .asObject() and strong references.
I am on oracle jdk 1.8.0_251, only because I was unable to get javaFX going under other JDKs I’ve tried. If it matters I am in eclipse 2019-12 on linux. Also, the spinners don't update each other at all in Debug mode, but they work (to start with) if I Run my code.
Why does it happen? My guesses are:
- I'm still suffering from garbage collection etc
- Something isn't keeping up with the fast clicking: my laptop's hardware, the linux OS, Eclipse, my jdk, javafx?
Can I somehow protect my code from this? Can I limit the clicking so that the spinner clicked only reacts to clicks if they are slow enough to keep the binding?
Please let me know if the behaviour described is unclear and I will upload a screen recording to youtube or something.
public class BindTwoSpinners extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
// Set up the topSpinner
Spinner<Integer> topSpinner = new Spinner<Integer> (1,12,1);
topSpinner.setEditable(true);
ObjectProperty<Integer> topObjectProp = new SimpleObjectProperty<>(1);
IntegerProperty topIntegerProperty = IntegerProperty.integerProperty(topObjectProp);
topSpinner.getValueFactory().valueProperty().bindBidirectional(topObjectProp);
// Set up the bottomSpinner
Spinner<Integer> bottomSpinner = new Spinner<Integer> (1,12,1);
bottomSpinner.setEditable(true);
ObjectProperty<Integer> bottomObjectProp = new SimpleObjectProperty<>(1);
IntegerProperty bottomIntegerProperty = IntegerProperty.integerProperty(bottomObjectProp);
bottomSpinner.getValueFactory().valueProperty().bindBidirectional(bottomObjectProp);
// Need to keep the reference as bidirectional binding uses weak references
// https://docs.oracle.com/javase/8/javafx/api/javafx/beans/property/IntegerProperty.html#bindBidirectional-javafx.beans.property.Property-
ObjectProperty<Integer> topIntegerPropertyAsObject = topIntegerProperty.asObject();
ObjectProperty<Integer> bottomIntegerPropertyAsObject = bottomIntegerProperty.asObject();
// Bind the two spinners
bottomSpinner.getValueFactory().valueProperty(). bindBidirectional(topIntegerPropertyAsObject);
VBox root = new VBox(10, topSpinner, bottomSpinner);
root.setAlignment(Pos.CENTER);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
来源:https://stackoverflow.com/questions/65462905/two-javafx-integer-spinners-bound-bidirectional-why-is-the-binding-unreliable