2014-05-12 79 views
1

在AS3中,stage.focus获取/设置具有焦点的显示对象。焦点可以分配给任何InteractiveObject实例及其继承的任何实例,如TextFields,Sprites和MovieClips。顺便提一句,我查看是否有任何这是ECMAScript规范的一部分(因为AS3和JavaScript有共同之处),并了解到在JavaScript中managing the focus (retrieving it in particular) is much more difficult;旧的浏览器不支持document.activeElement属性,甚至更新的浏览器仅限于返回与输入相关的元素。如果没有这样的元素有焦点,所有主流浏览器都返回body元素 - 除了IE 9,它返回html元素,Chrome 26在XHTML文档中返回false,但显然你可以使用document.querySelector(':focus')。在AS3中,什么属性决定InteractiveObject是否可以通过鼠标点击来获得舞台焦点?

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

当我第一次将事件监听器附加到舞台上并且侦听了FocusEvent.FOCUS_IN事件时,当我单击了舞台上创建的MovieClip对象时,它并未触发,这导致我得出结论:MovieClips/Sprites/InteractiveObjects在默认情况下不会通过单击或切换获得舞台焦点。同时,如果我将tabEnabled或buttonMode属性设置为true,则该事件在单击对象时触发。顺便提一句,tabEnabled的文档说,当Sprite.buttonMode为true时它会自动为true,所以tabEnabled似乎是感兴趣的属性(另外,buttonMode还启用其他功能,例如当按下Enter或Space键时触发点击事件该对象具有焦点)。

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

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

在JavaScript中,HTML5规范列出了一系列必须满足的条件,以使对象被视为“可聚焦”:“如果满足以下所有条件,则元素是可聚焦的:1.元素的tabindex焦点标志被设置2.元素被渲染或者是代表嵌入内容的画布元素的后代3.元素不是inert *该元素未被禁用。

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

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

回答

1

当你认为,这是的tabEnabled属性,需要设置,以确保对InteractiveObject能够获得通过用户输入的焦点,但是为了清楚起见,我会扩大有点我的回答:

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

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

为了更好地理解AS3中的焦点是如何工作的,人们可以说一个对象不会关注焦点,它会给予焦点。焦点由舞台管理,并且tabEnabled是舞台的一个指示器,以便知道它是否应该将焦点放到某个物体上。

附录:tabEnabled属性默认为false,因为AS3估计大多数InteractiveObject不需要焦点。毕竟,一个objet可以接受点击而不需要关注。

+0

感谢您的一个伟大和完整的答案。我发现可以通过FocusEvent.MOUSE_FOCUS_CHANGE和FocusEvent.KEY_FOCUS_CHANGE事件覆盖整个焦点系统,因为这些事件在FOCUS_IN和FOCUS_OUT事件之前并且可以取消,这与FOCUS_IN/OUT事件不同。更重要的是,MOUSE_FOCUS_CHANGE事件中目标和相关对象都被填充(即非空),即使它由于被点击的对象具有tabEnabled为假而生成了与null相关的对象的FOCUS_OUT事件。这是改变默认行为的关键。 – Triynko

+0

也想提到,尽管文档声称mouseEnabled阻止鼠标事件以及“其他用户输入事件,如键盘事件”,但它是错误的,因为尽管mouseEnabled(和mouseChildren)被设置为false,但具有焦点的对象仍然接收键盘事件。 – Triynko

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事件将具有空相关对象。

因此,如果您取消取决于查看tabEnabled值的默认行为,你可以选择将始终手动尽管查看tabEnabled是假的焦点分配给相关的对象,所以点击鼠标依旧会触发FOCUS_OUT事件,但他们永远不会有空的相关对象。

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

我创建的焦点管理器甚至有一个“nullFocus”属性,它允许您指定一个特定的对象作为应该有焦点的对象,否则焦点将变为空,确保焦点永远不会为空,并且事件总是可处理的。

+0

我发现了一个错误,当然。当点击的对象已经拥有焦点时,播放器无法分派MOUSE_FOCUS_CHANGE事件(对,因为点击的对象已经拥有焦点),但是它随后继续将焦点设置为null(对,因为非tabEnabled对象,当被点击时,导致焦点变为空),所以如果你甚至可以认为它是一个边缘情况,那么你无法防止那种边缘情况下的行为。通常情况下,非tabEnabled对象永远不会收到焦点,但是当您手动分配焦点时,它的有效状态只是处理错误。 – Triynko

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; 
     } 
    } 
} 

我意识到这是一个有些粗糙的解决方案,以一个比较复杂的问题,但所分配的索引更容易实现标签式的处理。

我希望这会有所帮助。

干杯

ps。对于任何微妙的拼写错误感到抱歉。我很快地输入了这些信息,不得不编辑几次。

相关问题