I am making a input field for keywords, and while the users writing I'm displaying suggestions for keyword on a list underneath the caret position. The input field is single line, so I am using the arrow up/down key to select a suggestion and Enter to insert it. And it's mostly working, with the big exception that the up/down key also changes the caret position to the begining/ending of the TextField
.
我正在为关键字创建输入字段,而用户正在编写我在插入符号位置下方的列表上显示关键字的建议。输入字段是单行,因此我使用向上/向下箭头键选择建议,然后按Enter键插入。它主要是工作,但有一个很大的例外,即向上/向下键也会将插入位置更改为TextField的开头/结尾。
I've tried using preventDefault()
and stopImmediatePropagation()
in the KeyboardEvent.KEY_DOWN
event listener that I also use to change the selected suggestion, but that does not change anything. I checked the carret has not yet moved when KeyboardEvent.KEY_DOWN
event is fired, bu visually I can see that it is being move before key is released (key up).
我已经尝试在KeyboardEvent.KEY_DOWN事件监听器中使用preventDefault()和stopImmediatePropagation(),我也用它来更改所选的建议,但这并没有改变任何东西。当我发现KeyboardEvent.KEY_DOWN事件被触发时,我检查了carret还没有移动,视觉上我可以看到它在释放键之前正在移动(键起来)。
I could just save the caret position, and then reset af the default behaviour. But that would properly involve some hack-like code using a timer.
我可以保存插入位置,然后重置默认行为。但这恰恰涉及一些使用计时器的类似黑客的代码。
So does anyone know how to prevent the default behaviour?
那么有谁知道如何防止默认行为?
6 个解决方案
#1
You can't prevent it, but you can reverse it. To do that you add to handlers with different priorities to the same event - KeyboardEvent.DOWN. One will execute before the TextField's , and save selection indexes and the other after, restoring them. Working code follows:
你不能阻止它,但你可以扭转它。为此,您可以向同一事件添加具有不同优先级的处理程序 - 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);
}
}
}
You might want better names for ssi (selection start index) and sei (selection end index), I was to lazy to find some. I think this solution was based on a post of Alex Harui, I don't remember exactly, but he's got a lot of good Flex related stuff on his blog.
你可能想要更好的ssi(选择开始索引)和sei(选择结束索引)的名字,我懒得找一些。我认为这个解决方案基于Alex Harui的帖子,我记不清楚了,但他的博客上有很多与Flex相关的好东西。
UPDATE: For the spark TextInput, preventing is not only possible, it is really easy. All you need to do is catch the event in the capture phase and stopping propagation. Code:
更新:对于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();
}
}
}
}
Note the last parameter in the addEventListener call, which is set to true in order for the handler to be called in the capture phase. Sadly this solution doesn't work for the mx TextInput, only for the spark one.
请注意addEventListener调用中的最后一个参数,该参数设置为true,以便在捕获阶段调用处理程序。遗憾的是,此解决方案不适用于mx TextInput,仅适用于spark one。
#2
I have posted a workaround for this problem here :
AS3: setSelection Up Arrow Override
我在这里发布了一个解决此问题的方法:AS3:setSelection Up Arrow Override
#3
The solution by bug-a-lot is intriguing - I didnlt think to use priorities. Instead, I made use of the different phases of the event process. The problem for me was to decide whether the arrow keys should advance or retreat one character within the given text field, or jump to the next or previous field in the form.
bug-a-lot的解决方案很有趣 - 我没想到要使用优先级。相反,我利用了事件过程的不同阶段。对我来说,问题是决定箭头键是应该在给定文本字段中前进还是后退一个字符,还是跳转到表单中的下一个或前一个字段。
First, I override the stage's event handling for the keys:
首先,我覆盖了阶段对键的事件处理:
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);
Note that I will process each key twice - before the system does it's wizardry (pretyping is called before the KEY_DOWN) so I can see where the caret is before Flash moves it, and after the system handles it (with typing, called after KEY_UP).
请注意,我将处理每个键两次 - 在系统执行它之前(在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 is a method of mine - all it does is turn those codes into convenient mnemonics. And isFocusInTextBox is a call to my focus manager - I replaced the standard focus manager to overcome other Flash issues. I just need to know if the thing is a text field or not.
getKeyString是我的一种方法 - 它只是将这些代码转换为方便的助记符。 isFocusInTextBox是对我的焦点管理器的调用 - 我替换了标准焦点管理器以克服其他Flash问题。我只需要知道这个东西是不是文本字段。
Next I have to process the key after Flash has already moved the caret and maybe even jumped to a new field, and by looking at the prior state, decide what Flash did and undo it and then do what ought to happen. My function "typing" has a lot of stuff not needed for this discussion, but the important thing it does is call allowKeyMapping. allowKeyMapping decides if the user entered forward arrow (or down arrow) from the last character position in the text field, or entered backward arrow from the beginning. If so, "typing" will tab to the next or previous field, respectively.
接下来我必须在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;
}
I am sorry I do not have a compact example prepared. I just thought it important to emphasize that you can get around Flash's penchant for doing things for you whether you want them to happen or not.
对不起,我没有准备好紧凑的例子。我只是觉得重要的是要强调一下,无论你是否希望它们发生,你都可以解决Flash为你做事的倾向。
#4
There could be some flick effect with the bug-a-lot's solution.
bug-a-lot的解决方案可能会有一些轻弹效应。
There is a working solution and good trick using stage.invalidate()
and stage's Event.RENDER
described here :
使用stage.invalidate()和stage的Event.RENDER有一个可行的解决方案和好方法:
AS3: setSelection Up Arrow Override
AS3:setSelection向上箭头覆盖
#5
This is my workaround for that problem. I'm sure there is a better way but it would probably require extending the TextInput control.
这是我解决该问题的方法。我确信有更好的方法,但可能需要扩展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);
}
}
Not sexy but it works.
不性感但它有效。
#6
by default event are priority 0 on UIComponent so you can always stop stop something to happen, here you prevent all KeyboardEvent.KEY_DOWN
默认情况下,事件在UIComponent上优先级为0,因此您可以随时停止发生某些事情,这里您可以阻止所有KeyboardEvent.KEY_DOWN
yourObject.addEventListener(KeyboardEvent.KEY_DOWN, _preventDefault, false, 1, true );
private function _preventDefault(event:KeyboardEvent):void
{
event.preventDefault();
event.stopImmediatePropagation();
}
#1
You can't prevent it, but you can reverse it. To do that you add to handlers with different priorities to the same event - KeyboardEvent.DOWN. One will execute before the TextField's , and save selection indexes and the other after, restoring them. Working code follows:
你不能阻止它,但你可以扭转它。为此,您可以向同一事件添加具有不同优先级的处理程序 - 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);
}
}
}
You might want better names for ssi (selection start index) and sei (selection end index), I was to lazy to find some. I think this solution was based on a post of Alex Harui, I don't remember exactly, but he's got a lot of good Flex related stuff on his blog.
你可能想要更好的ssi(选择开始索引)和sei(选择结束索引)的名字,我懒得找一些。我认为这个解决方案基于Alex Harui的帖子,我记不清楚了,但他的博客上有很多与Flex相关的好东西。
UPDATE: For the spark TextInput, preventing is not only possible, it is really easy. All you need to do is catch the event in the capture phase and stopping propagation. Code:
更新:对于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();
}
}
}
}
Note the last parameter in the addEventListener call, which is set to true in order for the handler to be called in the capture phase. Sadly this solution doesn't work for the mx TextInput, only for the spark one.
请注意addEventListener调用中的最后一个参数,该参数设置为true,以便在捕获阶段调用处理程序。遗憾的是,此解决方案不适用于mx TextInput,仅适用于spark one。
#2
I have posted a workaround for this problem here :
AS3: setSelection Up Arrow Override
我在这里发布了一个解决此问题的方法:AS3:setSelection Up Arrow Override
#3
The solution by bug-a-lot is intriguing - I didnlt think to use priorities. Instead, I made use of the different phases of the event process. The problem for me was to decide whether the arrow keys should advance or retreat one character within the given text field, or jump to the next or previous field in the form.
bug-a-lot的解决方案很有趣 - 我没想到要使用优先级。相反,我利用了事件过程的不同阶段。对我来说,问题是决定箭头键是应该在给定文本字段中前进还是后退一个字符,还是跳转到表单中的下一个或前一个字段。
First, I override the stage's event handling for the keys:
首先,我覆盖了阶段对键的事件处理:
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);
Note that I will process each key twice - before the system does it's wizardry (pretyping is called before the KEY_DOWN) so I can see where the caret is before Flash moves it, and after the system handles it (with typing, called after KEY_UP).
请注意,我将处理每个键两次 - 在系统执行它之前(在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 is a method of mine - all it does is turn those codes into convenient mnemonics. And isFocusInTextBox is a call to my focus manager - I replaced the standard focus manager to overcome other Flash issues. I just need to know if the thing is a text field or not.
getKeyString是我的一种方法 - 它只是将这些代码转换为方便的助记符。 isFocusInTextBox是对我的焦点管理器的调用 - 我替换了标准焦点管理器以克服其他Flash问题。我只需要知道这个东西是不是文本字段。
Next I have to process the key after Flash has already moved the caret and maybe even jumped to a new field, and by looking at the prior state, decide what Flash did and undo it and then do what ought to happen. My function "typing" has a lot of stuff not needed for this discussion, but the important thing it does is call allowKeyMapping. allowKeyMapping decides if the user entered forward arrow (or down arrow) from the last character position in the text field, or entered backward arrow from the beginning. If so, "typing" will tab to the next or previous field, respectively.
接下来我必须在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;
}
I am sorry I do not have a compact example prepared. I just thought it important to emphasize that you can get around Flash's penchant for doing things for you whether you want them to happen or not.
对不起,我没有准备好紧凑的例子。我只是觉得重要的是要强调一下,无论你是否希望它们发生,你都可以解决Flash为你做事的倾向。
#4
There could be some flick effect with the bug-a-lot's solution.
bug-a-lot的解决方案可能会有一些轻弹效应。
There is a working solution and good trick using stage.invalidate()
and stage's Event.RENDER
described here :
使用stage.invalidate()和stage的Event.RENDER有一个可行的解决方案和好方法:
AS3: setSelection Up Arrow Override
AS3:setSelection向上箭头覆盖
#5
This is my workaround for that problem. I'm sure there is a better way but it would probably require extending the TextInput control.
这是我解决该问题的方法。我确信有更好的方法,但可能需要扩展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);
}
}
Not sexy but it works.
不性感但它有效。
#6
by default event are priority 0 on UIComponent so you can always stop stop something to happen, here you prevent all KeyboardEvent.KEY_DOWN
默认情况下,事件在UIComponent上优先级为0,因此您可以随时停止发生某些事情,这里您可以阻止所有KeyboardEvent.KEY_DOWN
yourObject.addEventListener(KeyboardEvent.KEY_DOWN, _preventDefault, false, 1, true );
private function _preventDefault(event:KeyboardEvent):void
{
event.preventDefault();
event.stopImmediatePropagation();
}