1

I post new question based on this previously code posted here (Filter users values on TextField input after a BindDirectional strategy betwen a Slider and min/max TextField)

My goal is simple, what is the best way to undo wrong TextField value (based on custom verification) after user lost the focus event on my value.

Only way is to access the oldValue before user overwrite with another focus event ?

Actually i have this simple code :

val myTextField = new TextField ()

def parseDouble(s: String) = try {
  Some(s.toDouble)
} catch {
  case _ ⇒ None
}

myTextField.focusedProperty().addListener(
  new ChangeListener[java.lang.Boolean]() { 
    override def changed(observable: ObservableValue[_ <: java.lang.Boolean], oldValue: java.lang.Boolean, newValue: java.lang.Boolean) {
      if (!newValue) {
        parseDouble(myTextField.textProperty().get()) match {
          case Some(d: Double) ⇒  // test on the double value entered by user
          case _ ⇒ // code to reset to old value ??
        }
      }
    }
  })

Update 1 :

I find discussion here : https://forums.oracle.com/forums/thread.jspa?threadID=2382472 about undo functionnality for TextField/TextArea and other source code about TextInputControlBehavior : https://forums.oracle.com/forums/thread.jspa?threadID=2438759&tstart=45

I find description of undo behavior implemented into javafx 2.2 here http://javafx-jira.kenai.com/browse/RT-7547 but i cannot find sample code...

Update 2 :

I find a post for public undo control API (roadmap fixed for 2.2.6) for TextInputControl here : http://javafx-jira.kenai.com/browse/RT-26575

TextInputBehaviorControl can be see here : https://bitbucket.org/shemnon/openjfx-rt/src/6696e9cea59c401d2637d82f9cf96a515d210203/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextInputControlBehavior.java

Update 3 :

Tadam !

Finally i found an horrible way to do that, i hope public API is for 2.2.6 version of javaFX ...

    val myTextField = new TextField ()
    
    def parseDouble(s: String) = try {
      Some(s.toDouble)
    } catch {
      case _ ⇒ None
    }
    

  myTextField.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(myTextField.textProperty().get()) match {
            case Some(d: Double) ⇒
              if (myTextField.minValue > d || d > myTextField.maxValue) {
                doubleField.getSkin.asInstanceOf[TextInputControlSkin[_, _]].getBehavior.asInstanceOf[TextInputControlBehavior[_]].callAction("Undo")
              } else {
                // Here you change value property of textField
              }
            case _ ⇒ myTextField.getSkin.asInstanceOf[TextInputControlSkin[_, _]].getBehavior.asInstanceOf[TextInputControlBehavior[_]].callAction("Undo")
          }
        }
      }
    })

I validate the answer if anybody find a better way to do that :)

Community
  • 1
  • 1
reyman64
  • 523
  • 4
  • 34
  • 73
  • Sounds like you already have the answer. – Andy Till Feb 05 '13 at 12:44
  • @Andy-till I'm not expert in javafx, or ui with event building :/ I search proper way to do this behavior, but if it's the only way to do that, i consider posting the source code here to help community. I edit with some path for discussion.. – reyman64 Feb 05 '13 at 12:49

1 Answers1

1

as I am currently working on a JavaFX with Scala solution too, I would like to try your example, but I can't get it compiled. Specifically doubleField and value.set are unknown!

I have some hints - First: there is an obvious code duplication, that could be easily solved by adding a condition to the case - the first case only holds if the condition (d in range) is fulfilled

case Some(d: Double) if (doubleField.minValue <= d && d <= doubleField.maxValue) ⇒
  value.set(d)
case _ ⇒ 
  doubleField.getSkin.asInstanceOf[TextInputControlSkin[_, _]].getBehavior.asInstanceOf[TextInputControlBehavior[_]].callAction("Undo")

Second: provide a wrapper for anonymous inner classes in Java - for instance the above ChangeListener could be wrapped like this:

implicit def unit2ChangeListener[T](f: (ObservableValue[_ <: T], T, T) => Unit) =
  new ChangeListener[T] {
    override def changed(observable: ObservableValue[_ <: T], oldValue: T, newValue: T) {
      f(observable, oldValue, newValue)
    }
}

These implicit conversions could be hidden in a util class (along with a nice unit2EventHandler) and imported to your application. This would lead to something a bit more readable (but still a little painful):

myTextField.focusedProperty().addListener(
  (observable: ObservableValue[_ <: java.lang.Boolean], 
     oldValue: java.lang.Boolean, newValue: java.lang.Boolean) =>
     if (!newValue) { ... }
)

Probably ScalaFx already provides something like this, but I haven't tried it yet.

michael_s
  • 2,515
  • 18
  • 24
  • Hi @michael_s, thanks for hints, and sorry for bad copy/paste, i update the source code : `doubleField` = `myTextField` .. If you want to see the real code source sample which work, and if you want to make some revision on it, thanks for the help in this hard way scala + javafx :) https://gist.github.com/reyman/4753927 – reyman64 Feb 11 '13 at 11:19