Skip to content

Instantly share code, notes, and snippets.

@reyman
Last active December 12, 2015 09:48
Show Gist options
  • Save reyman/4753927 to your computer and use it in GitHub Desktop.
Save reyman/4753927 to your computer and use it in GitHub Desktop.
/*
* Copyright (C) 2011 srey
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.geocite.simprocess.javafx.ui.textfield
import javafx.scene.control._
import javafx.beans.property._
import scala.Predef
import javafx.beans.value.{ ObservableValue, ChangeListener }
import javafx.scene.input.{ KeyCode, KeyEvent }
import javafx.event.EventHandler
import com.sun.javafx.scene.control.skin.TextInputControlSkin
import com.sun.javafx.scene.control.behavior.TextInputControlBehavior
// Stackoverflow question by me :
//http://stackoverflow.com/questions/14693177/filter-users-values-on-textfield-input-after-a-binddirectional-strategy-betwen-a
class DoubleTextField(var minValue: Double, var maxValue: Double, val initialValue: Double) extends TextField {
require(minValue < maxValue, "DoubleField min value " + minValue + " greater than max value " + maxValue)
require(maxValue > minValue, "DoubleField max value " + minValue + " less than min value " + maxValue)
//require(!((minValue <= initialValue) && (initialValue <= 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[_ <: Number], oldValue: Number, newValue: Number) {
if (newValue == null) {
doubleField.setText("")
} else {
if (newValue.doubleValue() < doubleField.minValue) {
value.setValue(doubleField.minValue)
return
}
if (newValue.doubleValue() > doubleField.maxValue) {
value.setValue(doubleField.maxValue)
return
}
if (newValue.doubleValue() == 0 && (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()
}
}
})
// ensure any entered values lie inside the required range.
/*this.textProperty().addListener(
new ChangeListener[String]() {
override def changed(observableValue: ObservableValue[_ <: String], oldValue: String, newValue: String) {
if (newValue == null || "".equals(newValue)) {
value.setValue(0)
return
}
parseDouble(newValue) match {
case Some(d: Double) ⇒
if (doubleField.minValue > d || d > 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 : http://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[_ <: 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 > d || d > doubleField.maxValue) {
doubleField.getSkin.asInstanceOf[TextInputControlSkin[_, _]].getBehavior.asInstanceOf[TextInputControlBehavior[_]].callAction("Undo")
} else {
value.set(d)
}
case _ ⇒ doubleField.getSkin.asInstanceOf[TextInputControlSkin[_, _]].getBehavior.asInstanceOf[TextInputControlBehavior[_]].callAction("Undo")
}
}
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment