У меня есть требование ограничить количество символов, которые пользователь может ввести в управление JavaFX TextField
. Я продлил TextField
такОграничение количества символов JavaFX TextField вызывает IndexOutOfBounds при Undo
public class LengthLimitedTextField extends TextField {
/**
* @param maxCharacters The max allowed characters that can be entered into this {@link TextField}.
*/
public LengthLimitedTextField(final int maxCharacters) {
final TextField thisField = this;
this.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
// Force correct length by deleting the last entered character if text is longer than maxCharacters
if (newValue.length() > maxCharacters) {
thisField.deleteNextChar();
}
}
});
}
}
Это работает по назначению. Однако скажем, что для определенного LengthLimitedTextField
значение maxCharacters
равно 3. Если пользователь вводит 4 или более символов и пытается отменить (через CTRL + Z или контекстное меню мыши), я получаю следующее Exception
, а текст оставлен без изменений.
java.lang.IndexOutOfBoundsException
at javafx.scene.control.TextInputControl.replaceText(TextInputControl.java:368)
at com.sun.javafx.scene.control.skin.TextFieldSkin.replaceText(TextFieldSkin.java:572)
at com.sun.javafx.scene.control.behavior.TextFieldBehavior.replaceText(TextFieldBehavior.java:159)
at com.sun.javafx.scene.control.behavior.TextInputControlBehavior$UndoManager.undo(TextInputControlBehavior.java:442)
at com.sun.javafx.scene.control.behavior.TextInputControlBehavior.callAction(TextInputControlBehavior.java:137)
at com.sun.javafx.scene.control.skin.TextInputControlSkin$ContextMenuItem$1.handle(TextInputControlSkin.java:595)
at com.sun.javafx.scene.control.skin.TextInputControlSkin$ContextMenuItem$1.handle(TextInputControlSkin.java:593)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:28)
at javafx.event.Event.fireEvent(Event.java:171)
at javafx.scene.control.MenuItem.fire(MenuItem.java:456)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1197)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer$6.handle(ContextMenuContent.java:1148)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer$6.handle(ContextMenuContent.java:1146)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:33)
at javafx.event.Event.fireEvent(Event.java:171)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3328)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3168)
at javafx.scene.Scene$MouseHandler.access$1900(Scene.java:3123)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1563)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2265)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:250)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:173)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:292)
at com.sun.glass.ui.View.handleMouseEvent(View.java:528)
at com.sun.glass.ui.View.notifyMouse(View.java:922)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
at java.lang.Thread.run(Thread.java:724)
Я не уверен, как я могу это решить. Возможное (но не идеальное) решение состояло в том, чтобы полностью отключить Undo/Redo, но это не представляется возможным без полного переопределения контекстного меню (которое в соответствии с этим SO answer не просто) и сочетания клавиш по умолчанию.
Так в конечном счете, мой вопрос имеет два аспекта:
Есть, возможно, еще один способ, которым я могу ограничить количество символов в TextField
, не бросая исключение на Undo? Или есть ли чистый способ полностью отключить Undo в приложении?
Редактировать: Я сделал еще несколько исследований и в соответствии с https://javafx-jira.kenai.com/browse/RT-30881 это, кажется, ошибка. См. this comment. Так, возможно, этого невозможно достичь? Я собираюсь оставить вопрос открытым в надежде, что у кого-то есть возможное обходное решение.
Всегда придумал решение для этого? – Tommo
Как правило, это плохая идея изменить состояние свойства во время прослушивания его изменения - вы можете уйти от него (свойства fx заботятся о циклах), но все же могут быть неприятные побочные эффекты (ошибка отменить может или не быть таким побочным эффектом, не копать). Если вы перешли к jdk8u40 и выше, [TextFormatter может прийти на помощь] (http://stackoverflow.com/a/33218556/203657) – kleopatra