本文介绍了限制JavaFX TextField的字符数会导致撤消时出现IndexOutOfBounds的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要求限制用户可以输入的字符数到 TextField JavaFX控件。我已扩展 TextField ,因此

I have the requirement to limit the number of characters a user can input into a TextField JavaFX control. I have extended TextField like so

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或鼠标上下文菜单),我收到以下异常,文本保持不变。

This does work as intended. However, lets say that for a particular LengthLimitedTextField the maxCharacters is set to 3. If the user enters 4 or more characters, and attempts to Undo (either via CTRL+Z or mouse context menu), I receive the following Exception and the text is left unchanged.

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)

我不知道我是怎么做的可以解决这个问题一个可能的(但不是理想的)解决方案是完全禁用撤消/重做,但如果没有完全覆盖上下文菜单(根据此,并不容易)和默认的键盘快捷键。

I'm not sure how I can resolve this. A possible (but not ideal) solution was to disable Undo/Redo completely, but that doesn't appear possible without completely override the context menu (which according to this SO answer, isn't easy) and the default keyboard shortcuts.

所以最终,我的问题是双重的:

So ultimately, my question is twofold:

是否有其他方法可以限制字符数一个 TextField 而没有在撤消上抛出异常?或者是否有一种干净的方法可以在应用程序中完全禁用撤消?

Is there possibly another way I can limit the number of characters of a TextField without throwing an exception on Undo? Or is there a clean way to completely disable Undo in the application?

编辑:我做了一些研究并根据这似乎是是个bug。参见。那么也许这是不可能实现的呢?我将打开这个问题,希望有人确实有可能的解决方法。

Edit: I did some more research and according to https://javafx-jira.kenai.com/browse/RT-30881 this appears to be a bug. See this comment. So perhaps this isn't possible to achieve then? I'm going to leave the question open in hopes someone does have a possible workaround.

推荐答案

我在这里怎么做:
我会使用普通的文本字段,并会添加一个事件过滤器。

Here how I would do it:I would use a normal textfield, and would add an event filter.

设置:

The set up:

TextField tx = new TextField();
        tx.addEventFilter(KeyEvent.KEY_TYPED, maxLength(3));

事件处理程序:

The event handler:

public EventHandler<KeyEvent> maxLength(final Integer i) {
        return new EventHandler<KeyEvent>() {

            @Override
            public void handle(KeyEvent arg0) {

                TextField tx = (TextField) arg0.getSource();
                if (tx.getText().length() >= i) {
                    arg0.consume();
                }

            }

        };

    }

这篇关于限制JavaFX TextField的字符数会导致撤消时出现IndexOutOfBounds的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-16 05:01