1

在 AS3 中,stage.focus 获取/设置具有焦点的显示对象。焦点可以分配给任何 InteractiveObject 实例以及从它继承的任何东西,例如 TextFields、Sprites 和 MovieClips。

顺便说一句,我查看了这是否属于 ECMAScript 规范的一部分(因为 AS3 和 JavaScript 有共同点)并了解到在 JavaScript 中管理焦点(特别是检索它)要困难得多;较旧的浏览器不支持 document.activeElement 属性,甚至较新的浏览器也仅限于返回与输入相关的元素。如果没有这样的元素具有焦点,所有主流浏览器都会返回 body 元素——除了 IE 9,它返回 html 元素,Chrome 26 在 XHTML 文档中返回 false,但显然你可以使用 document.querySelector(':focus')。

与 JavaScript 相比,我发现 AS3 非常统一和一致,任何 InteractiveObject 都可以接收键盘焦点;但是,默认情况下,对象(除了 TextField 和 SimpleButton 实例)不会通过鼠标或键盘交互获得焦点。

当我第一次将事件侦听器附加到舞台并侦听 FocusEvent.FOCUS_IN 事件时,当我单击在舞台上创建的 MovieClip 对象时它没有触发,这使我得出结论 MovieClips/Sprites/InteractiveObjects 确实如此默认情况下不会通过单击或 Tab 键获得舞台焦点。

同时,如果我将 tabEnabled 或 buttonMode 属性设置为 true,则在单击对象时会触发事件。顺便说一句,tabEnabled 的文档说当 Sprite.buttonMode 为真时它自动为真,因此 tabEnabled 似乎是感兴趣的属性(此外,buttonMode 还启用其他功能,例如在按下回车键或空格键时触发点击事件对象具有焦点)。

我只是想知道 tabEnabled 是否是确保交互式对象在单击时接收舞台焦点的正确方法。尽管 tabEnabled 的文档说它会导致对象包含在 [keyboard] 选项卡排序中,但它没有特别提到鼠标交互,也没有提到任何通用状态,如“可以接收焦点”。似乎任何交互式对象都可以通过将 stage.focus 设置为该对象来手动分配焦点。

InteractiveObject的“tabEnabled”属性是控制是否可以通过键盘和鼠标交互分配焦点的主要属性是否正确?

在 JavaScript 中,HTML5 规范列出了一系列更复杂的条件,这些条件必须满足才能使对象被视为“可聚焦”:“如果满足以下所有条件,则元素是可聚焦的: 1. 元素的 tabindex 焦点标志是2. 元素要么正在渲染,要么是表示嵌入内容的画布元素的后代。3. 元素不是惰性的。*元素未被禁用。

更新:经过仔细检查,虽然 AS3 没有通用的“启用”属性,但似乎“mouseEnabled”功能类似,因为当设置为 false 时,“实例不接收任何鼠标事件(或其他用户输入事件,如键盘事件)。”

更新到第一次更新:包含短语“(或其他用户输入事件,如键盘事件)”的文档是错误的,因为尽管 mouseEnabled 设置为 false,但焦点对象仍会收到按键向下/向上事件。

4

3 回答 3

1

正如您所推测的,需要设置tabEnabled属性以确保 InteractiveObject 可以通过用户输入获得焦点,但为了清楚起见,我将扩展一下我的答案:

任何 InteractiveObject 都可以拥有焦点,无论它的属性如何。但是,有一些属性决定了如何获得焦点以及焦点在哪里。

  • Stage.focus指示当前哪个 InteractiveObject 具有焦点;此方法不是只读的,设置它会将焦点切换到给定的 InteractiveObject;以编程方式更改应用程序中处理焦点的方式很有用。
  • InteractiveObject.tabEnabled使实例能够通过用户操作接收焦点;表示单击、切换和使用箭头键。请注意,此属性不允许实例接收用户输入;它只允许舞台将焦点放在此实例上。
  • InteractiveObject.tabIndex允许通过动画设置标签顺序。它仅适用于制表符;使用箭头键忽略这一点。
  • InteractiveObject.mouseEnabled与焦点无关。它允许实例接收鼠标事件。

为了更好地理解焦点在 AS3 中的工作原理,可以说一个对象没有获得焦点,而是给予了焦点。焦点由 Stage 管理,tabEnabled 是 Stage 知道是否应该将焦点赋予对象的指示器。

附录:tabEnabled 属性默认为 false,因为 AS3 估计大多数 InteractiveObject 不需要焦点。毕竟,一个对象可以在不需要焦点的情况下接收点击。

于 2014-05-13T08:45:57.513 回答
0

我已经将另一个帖子标记为答案,但我只是想添加一些额外的信息。

FocusEvent.MOUSE_FOCUS_CHANGE 和 FocusEvent.KEY_FOCUS_CHANGE 在 FOCUS_IN 和 FOCUS_OUT 事件之前并且是可取消的,这与 FOCUS_IN/OUT 事件不同。

更重要的是,目标和相关对象都在 MOUSE_FOCUS_CHANGE 事件中填充(即非空),而如果单击对象的 tabEnabled 值为 false,则紧随其后的 FOCUS_OUT 事件将具有空相关对象。

通过在舞台的捕获阶段处理 MOUSE_FOCUS_CHANGE 和 KEY_FOCUS_CHANGE 事件,您可以覆盖整个焦点更改系统的默认行为,甚至可以防止焦点因鼠标单击而变为空。

例如,单击对象时的默认行为(无论 tabEnabled 是 true 还是 false)是引发 MOUSE_FOCUS_CHANGE 事件,该事件包括当前具有焦点的对象以及单击的对象。然后,有条件地:

  • 如果单击的对象具有 tabEnabled = true,则将为其分配焦点,并且 FOCUS_OUT/IN 事件将填充目标对象和相关对象。
  • 另一方面,如果单击的对象的 tabEnabled = false,则焦点设置为 null,并且 FOCUS_OUT 事件将具有 null 相关对象。

因此,如果您取消依赖于 tabEnabled 值的默认行为,您可以选择始终手动将焦点分配给相关对象,尽管 tabEnabled 为 false,因此鼠标单击仍会触发 FOCUS_OUT 事件,但它们会永远不会有空相关对象。

同样,您可以覆盖键盘引发的焦点更改的默认行为。我的 KEYBOARD_FOCUS_CHANGE 事件处理程序基于一个类,该类维护自定义焦点循环数组的可推送/可弹出堆栈,因此当按下选项卡时,它会检查当前焦点对象是否处于活动状态在堆栈顶部循环(或者是活动循环中对象的子/孙),如果是这样,它将焦点分配给下一个索引位置的对象(如果按下 shift 键,则将焦点分配给前一个)。如果对象不在循环中,它(基于设置)自动将焦点分配给活动循环中恰好位于堆栈顶部的第一个对象。它甚至可以防止焦点离开循环(焦点对象必须在循环中或循环中对象的后代)。循环可以通过公共方法进行更改,并且可以在打开和关闭具有不同控件集的对话框窗口时分配预定义的控件集。当您将新的控件数组推送到对话框窗口的堆栈时,它会备份当前焦点对象和当前焦点数组,然后将焦点移动到新数组中。当您弹出堆栈时,它会恢复旧数组并将焦点返回到备份时具有焦点的对象。这一切都运作良好,并且比默认机制更精确和可控。

我构建的焦点管理器甚至有一个“nullFocus”属性,它允许您将特定对象指定为当焦点变为空时应该具有焦点的对象,确保焦点永远不会真正为空并且事件始终是可处理的.

于 2014-05-20T16:46:28.543 回答
0

我知道这是一个老问题,但我一直在研究焦点切换一段时间,因为客户有一个新的请求。他们希望小键盘上的 + 键像选项卡一样,并在文本框之间更改焦点。

我是如何通过我在早期编程时代建立的一些技巧来实现它的。

我写了一个生成文本框的函数(如下):

function mkText(xpos,ypos,h,w,l:int,multi,sel,bor:Boolean,borCol:uint):TextField{

        var textInput = new TextField();
        textInput.x = xpos;
        textInput.y = ypos;
        textInput.height = h;
        textInput.width = w;
        textInput.maxChars = l;
        textInput.multiline = multi;
        textInput.selectable = sel;
        textInput.border = bor;
        textInput.borderColor = borCol;
        addChild(textInput);
        return textInput;
    }

有了这个,我可以在一个带有数组的循环中创建文本字段,例如:

    for(var i:int=0;i<8;i++)
{
    cForm[i] = mkText(cFormXpos,cFormYpos,27,69,2,false,true,true,0x000000);
    cForm[i].type = TextFieldType.INPUT;
    cForm[i].restrict = "0-9";
    cForm[i].defaultTextFormat = txFormat;
    cFormYpos += cForm[i].height + 13;
}

循环的每次运行都将创建一个具有动态分配的实例名称的新文本字段,您可以检查是否跟踪数组中任何元素的名称,例如 instance1、instance2 等。其中的每一个都可以由它们的数组位置以及甚至批量格式化或单独引用。使用这种方法,我使用增量器和通用 stage.focus 属性在它们之间切换。

function keyBind(e:KeyboardEvent)
{
    if(e.keyCode == 107)
    {
        stage.focus = cForm[tabOrder];
        if(tabOrder < 8)
        {
            tabOrder++;
        }
        else
        {
            tabOrder = 0;
        }
    }
}

我意识到对于更复杂的问题,这是一个有点粗略的解决方案,但是分配的索引可以更容易地实现制表符式处理。

我希望这有帮助。

干杯

附言。对于任何细微的拼写错误,我们深表歉意。我很快就输入了这个,不得不编辑了几次。

于 2015-11-04T15:14:56.300 回答