如何防止TextField中的箭头向上/向下默认行为?

时间:2009-06-19 14:29:56

标签: flex flash actionscript-3 textfield

我正在为关键字创建一个输入字段,而用户正在编写我在插入符号位置下方的列表中显示关键字的建议。 输入字段是单行,所以我使用向上/向下箭头键选择建议,然后按Enter键插入。 它主要起作用,但有一个很大的例外,即向上/向下键也会将插入符号位置更改为TextField的开头/结尾。

我尝试在preventDefault()事件监听器中使用stopImmediatePropagation()KeyboardEvent.KEY_DOWN,我也用它来更改所选的建议,但这并没有改变任何内容。 当KeyboardEvent.KEY_DOWN事件被触发时,我检查了carret还没有移动,视觉上我可以看到它在释放键之前正在移动(键入)。

我可以保存插入位置,然后重置默认行为。但这恰恰涉及一些使用计时器的类似黑客的代码。

那么有人知道如何防止默认行为吗?

6 个答案:

答案 0 :(得分:6)

你不能阻止它,但你可以扭转它。为此,您可以向同一事件添加具有不同优先级的处理程序 - KeyboardEvent.DOWN。一个将在TextField之前执行,并保存选择索引,另一个在恢复之后执行。工作代码如下:

    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;

    import mx.controls.TextInput;
    import mx.events.FlexEvent;

    public class FooledTextInput extends TextInput
    {
        private var ssi : int = 0;
        private var sei : int = 0;

        public function FooledTextInput()
        {
            super();

            this.addEventListener(KeyboardEvent.KEY_DOWN, onBeforeKeyDown, false, 10000);
            this.addEventListener(KeyboardEvent.KEY_DOWN, onAfterKeyDown, false, -10000);
        }

        private function onBeforeKeyDown(e : KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                ssi = this.selectionBeginIndex;
                sei = this.selectionEndIndex;
            }   
        } 

        private function onAfterKeyDown(e : KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                this.setSelection(ssi, sei);
            }   
        } 
    }

你可能想要更好的ssi(选择开始索引)和sei(选择结束索引)的名字,我懒得找一些。 我认为这个解决方案基于Alex Harui的帖子,我记不清楚了,但他的博客上有很多与Flex相关的好东西。

UPDATE:对于spark TextInput,不仅可以防止,它非常容易。您需要做的就是在捕获阶段捕获事件并停止传播。代码:

package
{
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;

    import spark.components.TextInput;

    public class HackedTextInput extends TextInput
    {
        public function HackedTextInput()
        {
            super();
            addEventListener(KeyboardEvent.KEY_DOWN, onBeforeKeyDown, true);
        }

        private function onBeforeKeyDown(e:KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                e.stopImmediatePropagation();
            }   
        }  
    }
}

注意addEventListener调用中的最后一个参数,该参数设置为true,以便在捕获阶段调用处理程序。遗憾的是,此解决方案不适用于mx TextInput,仅适用于spark one。

答案 1 :(得分:4)

我在这里发布了这个问题的解决方法:
AS3: setSelection Up Arrow Override

答案 2 :(得分:1)

bug-a-lot的解决方案很有趣 - 我没想过要使用优先级。相反,我利用了事件过程的不同阶段。对我来说,问题是决定箭头键是应该在给定文本字段中前进还是后退一个字符,或者跳转到表单中的下一个或上一个字段。

首先,我覆盖了阶段对键的事件处理:

stage.addEventListener(KeyboardEvent.KEY_UP, typing);
// Sneak in before the normal processing handles right and left arrow keystrokes.
stage.addEventListener(KeyboardEvent.KEY_DOWN, pretyping, true, 10); 

请注意,我将处理每个键两次 - 在系统执行它之前(在KEY_DOWN之前调用pretyping),这样我就可以在Flash移动之前看到插入符号的位置,并在系统处理它之后(通过键入,调用在KEY_UP之后。

/** Capture prior state of text field so we can later tell if user should tab to next field or previous field. */
private function pretyping(evt:KeyboardEvent):void {
    var keyString:String = Configuration.getKeyString(evt);
    if (isFocusInTextBox()) {
        var tf:TextField = getFocus() as TextField;
        capturePhaseCaret = tf.caretIndex;
    }
}

getKeyString是我的一种方法 - 它只是将这些代码转换为方便的助记符。 isFocusInTextBox是对我的焦点管理器的调用 - 我替换了标准焦点管理器以克服其他Flash问题。我只需要知道这个东西是不是文本字段。

接下来,我必须在Flash移动了插入符之后处理该键,甚至可能跳转到一个新字段,并通过查看先前的状态,决定Flash做了什么并将其撤消,然后执行应该发生的事情。我的函数“打字”有很多本讨论不需要的东西,但重要的是调用allowKeyMapping。 allowKeyMapping决定用户是否从文本字段中的最后一个字符位置输入了向前箭头(或向下箭头),或者从开头输入了向后箭头。如果是这样,“输入”将分别标记到下一个或上一个字段。

    /** Prefer default behavior and do not allow certain kestrokes to be reinterpreted by key mappings, such as left and right cursor keys in text boxes. */
    private function allowKeyMapping(keyString:String) {
        var allow:Boolean;
        // If focus is in a text field, allow right arrow to advance to next field only if caret is at end of text.
        // Conversely, allow left arrow to back up to previous field only if caret is at beginning of text.
        // The trick is that the normal processing of keystrokes by TextFields occurs before this method is called,
        // so we need to know the caret position from before the key was pressed, which we have stored in capturePhaseCaret, set in pretyping.
        if (isDragging) {
            allow = false;
        }
        else if (isFocusInTextBox()) {
            var tf:TextField = getFocus() as TextField;
            if (keyString == Configuration.LEFT_CURSOR_KEY) {
                allow = tf.caretIndex == 0 && capturePhaseCaret == 0;
            }
            else if (keyString == Configuration.RIGHT_CURSOR_KEY) {
                allow = tf.caretIndex == tf.text.length && capturePhaseCaret == tf.text.length;
            }
            else {
                allow = true;
            }
        }
        else {
            allow = true;
        }
        return allow;
    }

对不起,我没有准备好紧凑的例子。我只是认为重要的是要强调一下,无论你是否希望它们发生,你都可以解决Flash为你做事的倾向。

答案 3 :(得分:1)

对于bug-a-lot的解决方案,可能会有一些轻弹效果。

使用此处描述的stage.invalidate()和舞台Event.RENDER有一个可行的解决方案和好方法:

AS3: setSelection Up Arrow Override

答案 4 :(得分:0)

这是我解决该问题的方法。我确信有更好的方法,但可能需要扩展TextInput控件。

private function onKeyDown(event:KeyboardEvent):void
{
    if(event.keyCode == flash.ui.Keyboard.UP)
    {
        var begin:int = textinput.selectionBeginIndex;
        var end:int = textinput.selectionEndIndex;
        textinput.setSelection(begin,end);
    }
}

不性感但有效。

答案 5 :(得分:0)

默认情况下,事件在UIComponent上为优先级0 所以你可以随时停止发生某些事情,这里你要阻止所有的KeyboardEvent.KEY_DOWN

yourObject.addEventListener(KeyboardEvent.KEY_DOWN, _preventDefault, false, 1, true );
private function _preventDefault(event:KeyboardEvent):void 
{
event.preventDefault();
event.stopImmediatePropagation();
}