Note that there are some explanatory texts on larger screens.

plurals
  1. POFilter users values on TextField input after a BindDirectional strategy betwen a Slider and min/max TextField
    primarykey
    data
    text
    <p>Using two <code>TextField</code> : <code>texMin</code> and <code>texMax</code> , i want to limit min and max values of my doubleSlider control (cf the custom ui control <code>DoubleSlider</code> here : <a href="http://code.google.com/p/javafx-widgets/source/browse/#svn%2Ftrunk%2FDoubleSlider%2Fsrc%2Fdouble_slider" rel="nofollow noreferrer">http://code.google.com/p/javafx-widgets/source/browse/#svn%2Ftrunk%2FDoubleSlider%2Fsrc%2Fdouble_slider</a> ) </p> <p>The DoubleBinded with StringConverter (double to string) works perfectly, but now i don't know how can i filter to get only correct values entered by user in the two <code>TextField</code> after it <code>ENTER</code> keypress..</p> <p>I don't know if a <code>setOnKeyReleasedEvent</code> filter on value entered by user can work with a <code>bindBidirectional</code> on properties. I think the <code>bindBidirectional</code> bypass my filter (fire an event each time the text change), but i'm not sure.</p> <pre><code> def sliderBlockFactory(slider: DoubleSlider): HBox = { val minText = new TextField() val maxText = new TextField() minText.setText(slider.getValue1().toString) maxText.setText(slider.getValue2().toString) slider.value1Property().addListener( new ChangeListener[Number]() { override def changed(ov: ObservableValue[_ &lt;: Number], old_val: Number, new_val: Number) { if (new_val.doubleValue() == null) { minText.setText("") } else { minText.setText(new_val.doubleValue().toString()) } } }) slider.value2Property().addListener( new ChangeListener[Number]() { override def changed(ov: ObservableValue[_ &lt;: Number], old_val: Number, new_val: Number) { if (new_val.doubleValue() == null) { maxText.setText("") } else { maxText.setText(new_val.doubleValue().toString()) } } }) minText.setPrefWidth(40) maxText.setPrefWidth(40) val converter: StringConverter[_ &lt;: Number] = new DoubleStringConverter() Bindings.bindBidirectional(minText.textProperty(), slider.value1Property(), converter.asInstanceOf[StringConverter[Number]]) Bindings.bindBidirectional(maxText.textProperty(), slider.value2Property(), converter.asInstanceOf[StringConverter[Number]]) val uiSliderBlock = new HBox() uiSliderBlock.getChildren.addAll(minText, slider, maxText) uiSliderBlock } def doubleSliderFactory(min: Double, max: Double): DoubleSlider = { val slider = new DoubleSlider() slider.setMin(min) slider.setMax(max) slider.setShowTickLabels(true) slider.setShowTickMarks(true) slider.setMajorTickUnit(50) slider.setMinorTickCount(25) slider.setSnapToTicks(true) slider.setPrefWidth(100) slider.setBlockIncrement(10) slider } val myDoubleSlider = sliderBlockFactory(doubleSliderFactory(0.0, 100.0)) </code></pre> <p><strong>UPDATE 1 :</strong> </p> <p>Thanks to comments, i modify my code source. I giveup DoubleStringConverter because my use case is too complex. I also translate java source code given in comments url into scala : </p> <pre><code>class DoubleTextField(var minValue: Double, var maxValue: Double, val initialValue: Double) extends TextField { require(minValue &lt; maxValue, "DoubleField min value " + minValue + " greater than max value " + maxValue) require(maxValue &gt; minValue, "DoubleField max value " + minValue + " less than min value " + maxValue) //require(!((minValue &lt;= initialValue) &amp;&amp; (initialValue &lt;= maxValue)), "DoubleField initialValue " + initialValue + " not between " + minValue + " and " + maxValue) val value: DoubleProperty = new SimpleDoubleProperty(initialValue) //scala parsing def parseDouble(s: String) = try { Some(s.toDouble) } catch { case _ ⇒ None } def getValue() = value.getValue() def setValue(newValue: Double) = value.setValue(newValue) def valueProperty(): DoubleProperty = value setText(initialValue.toString()) val doubleField: DoubleTextField = this // make sure the value property is clamped to the required range // and update the field's text to be in sync with the value. value.addListener(new ChangeListener[Number]() { override def changed(observableValue: ObservableValue[_ &lt;: Number], oldValue: Number, newValue: Number) { if (newValue == null) { doubleField.setText("") } else { if (newValue.doubleValue() &lt; doubleField.minValue) { value.setValue(doubleField.minValue) return } if (newValue.doubleValue() &gt; doubleField.maxValue) { value.setValue(doubleField.maxValue) return } if (newValue.doubleValue() == 0 &amp;&amp; (textProperty().get() == null || "".equals(textProperty().get()))) { // no action required, text property is already blank, we don't need to set it to 0. } else { doubleField.setText(newValue.toString()) } } } }) // restrict key input to numerals. this.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler[KeyEvent]() { override def handle(keyEvent: KeyEvent) { if (!"0123456789".contains(keyEvent.getCharacter())) { keyEvent.consume() } } }) // i don't want a realtime change on my textfield, // so i prefer a validate method like focusedProperty (see below) /*this.textProperty().addListener( new ChangeListener[String]() { override def changed(observableValue: ObservableValue[_ &lt;: String], oldValue: String, newValue: String) { if (newValue == null || "".equals(newValue)) { value.setValue(0) return } parseDouble(newValue) match { case Some(d: Double) ⇒ if (doubleField.minValue &gt; d || d &gt; doubleField.maxValue) { textProperty().setValue(oldValue) value.set(oldValue.toDouble) } else { value.set(d) } case _ ⇒ oldValue //reset to old value } } })*/ // Detect a change in focus on the text field.. If we lose the focus we take appropriate action // problem with boolean : https://stackoverflow.com/questions/11377350/scala-java-interop-class-type-not-converted this.focusedProperty().addListener( new ChangeListener[java.lang.Boolean]() { db ⇒ override def changed(observable: ObservableValue[_ &lt;: java.lang.Boolean], oldValue: java.lang.Boolean, newValue: java.lang.Boolean) { if (!newValue) { parseDouble(doubleField.textProperty().get()) match { case Some(d: Double) ⇒ if (doubleField.minValue &gt; d || d &gt; doubleField.maxValue) { textProperty().setValue(doubleField.minValue.toString) value.set(textProperty().get().toDouble) } else { value.set(d) } case _ ⇒ println("error") //reset to old value } } } }) } </code></pre> <p>The corrected code source for <code>DoubleSlider</code> update by <code>DoubleTextField</code> :</p> <pre><code>// inspired by : // https://gist.github.com/1962045 // https://stackoverflow.com/questions/14138082/java-fx-bidirectional-bindings-of-different-properties // https://forums.oracle.com/forums/thread.jspa?threadID=2311243 def sliderBlockFactory(slider: DoubleSlider): HBox = { val minText = new DoubleTextField(slider.getMin, slider.getMax, slider.getMin) val maxText = new DoubleTextField(slider.getMin, slider.getMax, slider.getMax) slider.value1Property().addListener( new ChangeListener[Number]() { override def changed(ov: ObservableValue[_ &lt;: Number], old_val: Number, new_val: Number) { if (new_val.doubleValue() == null) { minText.setText("") } else { //set new min value of maxText maxText.minValue = new_val.doubleValue() } } }) slider.value2Property().addListener( new ChangeListener[Number]() { override def changed(ov: ObservableValue[_ &lt;: Number], old_val: Number, new_val: Number) { if (new_val.doubleValue() == null) { maxText.setText("") } else { //set new max value of minText minText.maxValue = new_val.doubleValue() } } }) minText.setPrefWidth(40) maxText.setPrefWidth(40) /*val converter: StringConverter[_ &lt;: Number] = new DoubleStringConverter() Bindings.bindBidirectional(minText.textProperty(), slider.value1Property(), converter.asInstanceOf[StringConverter[Number]]) Bindings.bindBidirectional(maxText.textProperty(), slider.value2Property(), converter.asInstanceOf[StringConverter[Number]]) */ minText.valueProperty().bindBidirectional(slider.value1Property()) maxText.valueProperty().bindBidirectional(slider.value2Property()) val uiSliderBlock = new HBox() uiSliderBlock.getChildren.addAll(minText, slider, maxText) uiSliderBlock } def doubleSliderFactory(min: Double, max: Double): DoubleSlider = { val slider = new DoubleSlider() slider.setMin(min) slider.setMax(max) slider.setShowTickLabels(true) slider.setShowTickMarks(true) slider.setMajorTickUnit(50) slider.setMinorTickCount(25) slider.setSnapToTicks(true) slider.setPrefWidth(100) slider.setBlockIncrement(10) slider } val myDoubleSlider = sliderBlockFactory(doubleSliderFactory(0.0, 100.0)) </code></pre> <p>Result :) </p> <p><img src="https://i.stack.imgur.com/19AoO.png" alt="enter image description here"></p> <p>This code works, values for min and max of each slider controls are updated correctly, but as you can see, when focus is left and if value are bad <strong>i can't retrieve the old value with focused event</strong>. My question is simple, is there any way to get the old values in the textField without using <code>changeListener</code> on <code>textProperty</code> ?</p> <p><strong>Update 2 :</strong> </p> <p>I found my answer here :</p> <p><a href="https://stackoverflow.com/questions/14707550/undo-behavior-on-textfield-value-based-on-value-verification-after-focus-lost">Undo behavior on textField value based on value verification after focus lost</a></p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload