1. 在Jre1.7版本中,KeyboardFocusManager,DefaultKeyboardFocusManager这两个类,与Component, WComponentPeer类一起完成了focus的主要逻辑实现。
DefaultKeyboardFocusManager是前者的系统默认实现。其单例注册在appcontext中,如果需要,程序员可以替代它,以扩展focus的逻辑实现。
appcontext.put(KeyboardFocusManager.class, new SelfKeyboardFocusManager());
2. Component中提供了requestFocus方法。而各个组件在初始化时都会安装默认的Listener。当这些Listener收到适当的事件通知后(比如mouse_press)即会调用这个方法。该方法首先判断该组件是否focusable,组件所依托窗口是否focusable,当前聚焦组件的InputVerifier是否验收输入等等,判断通过后请求重量级组件容器的peer.requestFocus。WComponentPeer中提供该requestFocus方法。该方法首先调用native processSynchronousLightweightTransfer,其会调用KeyboardFocusManager .processSynchronousLightweightTransferr,作用是如果当前request组件的重量级组件容器正对应当前底层系统的聚焦组件,而且当前没有任何切换焦点的heavyweightRequests,这时将直接切换focus变量KeyboardFocusManager.focusOwner。
如果上述调用没有顺利完成并返回true,则会调用native _requestFoucs。该方法会调用KeyboardFocusManager .shouldNativelyFocusHeavyweight,其作用就是完成request登记,并在登记时间戳以正确缓存处理后续进入EDT的Keyevent处理。
Request登记的结构为KeyboardFocusManager.heavyweightRequests=
LinkedList< HeavyweightFocusRequest >
-- HeavyweightFocusRequest{
Component heavyweight;
LinkedList<LightweightFocusRequest> lightweightRequests,登记方式分为3种:
a. 如果发出requestFocus的组件的重量级组件容器正对应当前底层系统的聚焦组件,而且当前没有任何切换焦点的heavyweightRequest,则增加一个heavyweightRequest并向Post-Qqeue post focus-event。
b. 如果发出requestFocus组件的重量级组件容器不对应当前底层系统的聚焦组件,而且当前没有任何切换焦点的heavyweightRequest;或者当前存在切换焦点的heavyweightRequest,而最后一个heavyweightRequest. Heavyweight!=当前request组件的重量级组件容器,则要增加一个heavyweightRequest,并同步通知底层系统进行重量级对等组件的focus切换。
c. 如果当前存在切换焦点的heavyweightRequest,而且最后一个heavyweightRequest. Heavyweight==当前requestFocus的组件的重量级组件容器,则直接在request.lightweightRequests追加一个LightweightFocusRequest。
3. EDT在逐个处理AWTEvent时,委托给EventQueue.dispatchEvent,继而委托给Component. dispatchEventImpl,该方法顺序执行下面的代码片段:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
/* focusManagerIsDispatching标志了该event;如果==true意味着该event不会交由KeyboardManager进行retarget及dispatch。而这两个动作主要完成的功能就是刷新java的全局focus变量。因此可以想象focusManagerIsDispatching==true的Focus_event是focus发生切换后的event,而focusManagerIsDispatching==false的是PrepareFocusEvent。*/
if (!e.focusManagerIsDispatching) {//----------PrepareFocusEvent
// Invoke the private focus retargeting method which provides
// lightweight Component supportF
/*通过retargetFocus,处理之前注册的request请求,最终激发出合适的CausedFocusEvent,交给下面的dispatch.
*/
if (e.isPosted) {
e = KeyboardFocusManager.retargetFocusEvent(e);
e.isPosted = true;
}
// Now, with the event properly targeted to a lightweight
// descendant if necessary, invoke the public focus retargeting
// and dispatching function
/*通过dispatch给注册的DefaultKeyboardFocusManager,最终更新了java的全局focus变量
*/
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().
dispatchEvent(e))
{
return;
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
4. 总之:
a. 轻量级组件的Mouse_Press Listener会requestFocus。request通过必要条件检查后会在KeyboardFocusManager.heavyweightRequests缓存列表登记,同时在一个列表中登记一个时间戳marker=当前系统时间。
b. 每一个KeyEvent都有一个发生时间when,这个发生时间认为是AWT-Windows loop底层event形成KeyEvent的时间。EDT在调用KeyboardFocusManager 。dispatchEvent处理一个KeyEvent时只要发现when晚于时间戳缓存列表中登记的第一个时间戳,就充分说明这是在某焦点切换请求发出后发生的键盘事件,则不应该将这个KeyEvent target到当前全局focus变量,因而这时暂将此KeyEvent缓存在另一个列表。
c. 根据前面的分析,在requestFocus时有3种情况,一种是新增heavyweightRequest,同时post给post-queue一个FocusEvent,一种是新增heavyweightRequest,同时因为要求底层系统切换重量级对等体而awt-loop到一个FocusEvent,这两种情况的request都在列表中期待对应FocusEvent到来再切换焦点。从登记时间戳开始,被awt-loop到的KeyEvent进入EDT时都将缓存下来,而一段时间后当期待的FocusEvent从post-queue进入event-queue并要在EDT中处理时,有充分的条件可以判断出此后再进入EDT的KeyEvent,都至少是request登记时间戳后发生的,则这时可以完成此request-删除该heavyweightRequest缓存条目,做focus实际切换,并将缓存的KeyEvent 及时间戳记录处理掉。而第3种情况是在requestFocus时可以在最末一个heavyweightRequest上直接追加LightWeightReuquest,那么当该heavyweightRequest期待的FocusEvent到来时,按前面所述处理完该request,再将后续LightWeightRequest保存引用到一个全局变量KeyboardFocusManager.currentLightweightRequests,再将此刻为止awt-loop至的post-queue的所有event完全flush到event-queue,再把一个要求循环处理所有currentLightweightRequests指向的LightWeightRequests的InvocationEvent post 到event-queue之后。这样当EDT开始处理该InvocationEvent时,有充分的条件可以判断出此后再进入EDT的KeyEvent,都至少是最后一个后续LightWeightRequest登记时间戳后发生的,则这时只需按该InvocationEvent执行即可,及逐个清理LightWeightRequest完成focus切换及处理时间戳和缓存KeyEvent。如果在循环处理过程中发生对某一个组件requestFocus调用,这时会根据处理之初currentLightweightRequests中是否只有单独1个request来确定能否processSynchronousLightweightTransferr,即如果有多个,则这时禁止processSynchronousLightweightTransferr以防止破坏了切换焦点的顺序。
d. 重量级组件不需要在Mouse_Press Listener request Focus,当被进行Mouse Press时,底层系统分发一个Focus Event,当进入EDT处理时,在jre1.7中通过KeyboardFocusManager.retargetUnexpectedFocusEventretarget,首先逐个剔除request后进行期待匹配(针对可能的底层分发-post-queue-event-queue中间环节Event的遗漏等例外情形),如果最后没有一个request匹配,则直接形成CausedFocusEvent交给后继dispatch完成焦点切换。更确切地说,对于jre1.7而言组件聚焦应该都通过requestFocus完成切换,不通过该方式的聚焦切换在retarget时将归属到Unexpected被处理,而重量级组件的这种聚焦正好通过unexpected完成。
5. 最后,个人认为jre1.7中存在一个可能的问题:每次dispatchEvent时都会在retargetFocusEvent里processCurrentLightweightRequests,这样不久破坏了4-c分析的时机逻辑了么?为什么要这样呢?
分享到:
相关推荐
### Java JSP 实现 JS 表单验证 在本文中,我们将探讨如何使用 JavaScript 在 Java JSP 页面上实现表单验证。此示例代码通过多种正则表达式和条件判断来确保用户输入的数据符合特定的标准。 #### 标题解读:Java ...
例如,Visual Studio 2010可以用于C#,但对Cobol的支持可能有限,可能需要结合其他工具如Micro Focus的Visual COBOL来实现Cobol和Java的开发。 3. **语法和数据类型**: - **COBOLCOBOL85COBOL**: 这可能是在讨论...
Java JsonPath实现是一种在Java程序中解析JSON对象的工具,类似于XPath在XML处理中的作用。JsonPath是由Goessner在2007年提出的概念,它提供了一种简洁的表达式语言,用于从JSON文档中提取数据。在Java中,我们可以...
Java 8是Java语言的一个重要版本,它引入了一系列创新特性,极大地提升了开发效率和代码的可读性。本文将深入探讨Java 8的几个关键特性,包括拉姆达表达式、流(Stream)以及默认方法。 1. **拉姆达表达式** (Lambda ...
基于JAVA的学生成绩管理系统的设计与实现 摘 要:本文按照目前流行的B/S体系结构模式,结合现有的学生成绩管理系统的现状,采用 SQL Server 2000数据库和JAVA技术,设计开发了学生成绩管理系统系统,本系统分为前台...
《聚焦幻灯片插件——focus.swf的详解与应用》 在网页设计中,吸引用户的注意力至关重要,而幻灯片展示就是一种有效的手段。本文将深入探讨一款名为"focus.swf"的幻灯片插件,它以其酷炫的播放效果和灵活的配置选项...
With a focus on practical examples and clear explanations, this book is an excellent resource for anyone looking to update their skills or start learning Java from scratch. By mastering the key ...
WMC FOCUS6.3 用于风力发电叶片结构设计专用软件,此文档为其API 二次开发结构,采用Python语言进行二次开发
### Java JSP+Servlet 实现登录网页设计 #### 项目背景 本项目旨在通过Java、JSP和Servlet技术实现一个简单的用户登录系统。系统的核心功能包括用户登录验证、数据库连接及数据操作等。 #### 技术栈 - **前端**: ...
#### 二、JAVA调用COBOL 1. **接口类**:为使JAVA程序能够调用COBOL程序,需要创建一些特殊的JAVA类来充当接口。这些类通常位于一个名为mfcobol.jar的JAR文件中。 2. **环境配置**:确保CLASSPATH环境变量包含了...
"focus.swf"即为一种实现焦点图切换功能的SWF文件,常用于广告展示或网站轮播图。本文将深入探讨focus.swf的图片切换原理、实现方式及其源代码分析。 1. **SWF文件简介** SWF全称为Small Web Format,是Adobe ...
总结来说,Java 中实现带复选框的树(CheckBox Tree)需要自定义 TreeNode 类(CheckBoxTreeNode),用于存储结点是否被选中的状态,并实现选中/取消选中时子结点和父结点的状态更新。同时,还需要创建一个 ...
[奥莱理] RESTful Java 开发 (Jax-RS 实现) (英文版) [奥莱理] RESTful Java with Jax-RS (E-Book) ☆ 图书概要:☆ Learn how to design and develop distributed web services in Java using RESTful ...
《用Java设计文本编辑器MiniEditor》是一款基于Java编程技术实现的轻量级文本编辑工具。这个项目旨在提供一个基础的文本编辑环境,允许用户进行基本的文字操作,如输入、复制、删除、选中、插入,以及查找和替换功能...
在Java编程语言中,事件处理是用户界面(UI)开发中的关键部分,它允许程序响应...`FocusEventShow.java`的实例代码展示了如何通过实现`FocusListener`或使用`FocusAdapter`来处理这些事件,进而提供更好的用户体验。
综上所述,AudioFocus是Android系统中实现音频流管理的关键机制,它确保了音频播放的流畅性和一致性,尤其是在多任务环境下。开发者需要理解并熟练运用AudioFocus,以优化其音频应用的功能和用户体验。在AudioFocus...
本篇文章将详细讲解如何使用Java实现HTTP POST客户端和服务器,并探讨相关知识点。 首先,让我们从服务器端开始。在Java中,我们可以使用内置的`HttpServer`类(来自`com.sun.net.httpserver`包)来创建一个简单的...
在Java编程语言中,构建定制的树型视图是一项常见的任务,特别是在开发用户界面或数据结构展示时。Java提供了一套强大的工具来帮助开发者创建这样的视图,这主要涉及到Java Swing库中的JTree组件。本篇文章将深入...
Java中的`JTable`是Swing库中的一个关键组件,用于在GUI应用程序中展示数据的二维表格形式。它提供了一种灵活的方式,可以方便地显示、编辑和操作数据。在这个实例中,我们主要探讨`JTable`的使用,以及如何在Java...
在Java编程中,构建一个能够展示系统目录树结构的控件是常见的需求,尤其是在开发桌面应用或者需要...提供的文本文件`java实现系统目录树控件.txt`可能包含了更详细的实现代码或示例,阅读它能帮助理解具体的实现细节。