Отменить поведение значения textField на основе проверки значения после потери фокуса

Я публикую новый вопрос на основе этого ранее размещенного здесь кода (Фильтровать значения пользователей при вводе TextField после стратегии BindDirectional между ползунком и min/max TextField)

Моя цель проста: как лучше всего отменить неправильное значение TextField (на основе пользовательской проверки) после того, как пользователь потерял событие фокуса на моем значении.

Единственный способ - получить доступ к oldValue до того, как пользователь перезапишет другое событие фокуса?

На самом деле у меня есть этот простой код:

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 ??
        }
      }
    }
  })

Обновление 1:

Я нахожу обсуждение здесь: https://forums.oracle.com/forums/thread.jspa?threadID=2382472 о функции отмены для TextField/TextArea и другой исходный код о TextInputControlBehavior: https://forums.oracle.com/forums/thread.jspa?threadID=2438759&tstart=45

Я нахожу описание поведения отмены, реализованного в javafx 2.2, здесь http://javafx-jira.kenai.com/browse/RT-7547, но я не могу найти пример кода...

Обновление 2:

Я нашел сообщение об общедоступном API управления отменой (исправлено для версии 2.2.6) для TextInputControl здесь: http://javafx-jira.kenai.com/browse/RT-26575

TextInputBehaviorControl можно посмотреть здесь: https://bitbucket.org/shemnon/openjfx-rt/src/6696e9cea59c401d2637d82f9cf96a515d210203/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextInputControlBehavior.java

Обновление 3:

Тадам!

Наконец, я нашел ужасный способ сделать это, я надеюсь, что общедоступный API предназначен для версии 2.2.6 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")
          }
        }
      }
    })

Я подтверждаю ответ, если кто-нибудь найдет лучший способ сделать это :)


person reyman64    schedule 05.02.2013    source источник
comment
Похоже, у вас уже есть ответ.   -  person Andy Till    schedule 05.02.2013
comment
@ Andy-till Я не эксперт в javafx или пользовательском интерфейсе с созданием событий: / Я ищу правильный способ сделать это, но если это единственный способ сделать это, я рассмотрю возможность размещения исходного кода здесь, чтобы помочь сообществу. Я редактирую с некоторым путем для обсуждения..   -  person reyman64    schedule 05.02.2013


Ответы (1)


поскольку в настоящее время я также работаю над решением JavaFX с Scala, я хотел бы попробовать ваш пример, но я не могу его скомпилировать. Конкретно doubleField и value.set неизвестны!

У меня есть несколько советов. Во-первых: существует очевидное дублирование кода, которое можно легко решить, добавив условие в случай - первый случай выполняется только в том случае, если условие (d в диапазоне) выполнено.

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

Во-вторых: предоставьте оболочку для анонимных внутренних классов в Java — например, вышеупомянутый ChangeListener может быть обернут следующим образом:

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)
    }
}

Эти неявные преобразования могут быть скрыты в классе util (вместе с хорошим обработчиком unit2EventHandler) и импортированы в ваше приложение. Это привело бы к чему-то более читабельному (но все же немного болезненному):

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

Вероятно, ScalaFx уже предоставляет что-то подобное, но я еще не пробовал.

person michael_s    schedule 09.02.2013
comment
Привет @michael_s, спасибо за подсказки и извините за неудачное копирование/вставку, я обновляю исходный код: doubleField = myTextField .. Если вы хотите увидеть реальный образец исходного кода, который работает, и если вы хотите внести в него некоторые изменения , спасибо за помощь в этом нелегком пути scala + javafx :) gist.github.com/reyman/4753927< /а> - person reyman64; 11.02.2013