窗口系统一般包含一个桌面GUI+若干应用程序GUI。每个GUI都由组件构成,每个组件都可以获得focus,获得focus的组件将获得之后的键盘事件,而任意时刻只有一个组件能获得focus。这个设计适用在当前所有的窗口系统,而跨各种系统的JAVA应用,其focus的表现也要遵循这个设计目标。
JAVA的组件分为重量级和轻量级组件,区别在于重量级组件实例的成员peer-对等体,其行为紧密依托本地系统的GUI行为函数库来进行实现。比如一个JFRAME,当setvisible时,会依托peer.show进行屏幕绘制行为,该行为会通过本地系统GUI行为函数库完成;这样一来,当其被点击时,本地系统会依据最初调用本地GUI函数绘制时留下的信息,从而能够经底层处理后(比如将该鼠标事件附加peer标记信息,同时可能经底层分析需要构造出一个可能的focus_gain事件,则在操作系统层面登记当前聚焦GUI组件等)准确将底层GUI事件派送给该JVM进程,该事件因而在jvm进程中的AWT-Windows线程loop获取到,并通过事件提供的peer标记最终确定目标为重量级组件JFRAME,因此一个source==JFRAME的AWTEvent被构造出来并最终分派给EDT进行后续处理。
事件机制是程序中家喻户晓的设计模式了。但是,看java的focus实现中对这个机制似乎多少有些不那么绝对的清晰J。
个人理解,事件的含义就是某种定义的情况发生了。比如点击鼠标这个动作可以说触发了多个事件,如press,release,click等,分别指发生了鼠标button1按下,放开,完成点击的情况。button1按下这个事件比起完成点击就要更基础一些,因为完成点击指的是一个由按下,放开动作序列组合的情况发生了。
那么对于focus,focus_gained,focus_lost这两个事件应该是指某组件获得焦点或失去焦点的情况发生了,反映在机器里,应该是某种指向当前聚焦组件的全局变量发生了更新。
然而在Java awt实现里,概念混乱出现啦。
如果awt_windows loop 到了focus事件,一,这个事件一定是目标向重量级组件的;二,此时,这个事件对于底层系统的对等组件,focus_gainded是发生了(底层系统标记当前聚焦组件的全局变量已经更新;底层操作系统没有mess,总是在真正focus改变后才分发focus事件),然而在java层面,截至到awt_windows loop 到底层focus事件并包装成FocusEvent放置到EVENT QUEUE时,java层面并没有更新jvm里的全局变量。所以我个人认为这个时候就不应该包装成FocusEvent,至少不应该叫这个名字,应该叫PrepareFocusEvent,嘿嘿。
澄清事件机制的概念后,回头看java focus 要实现的目标。
1. 最简单的设计思路是提供一个setfocus调用API,该API来更新一个全局变量。EDT每次处理一个keyevent将根据当前全局变量进行target。最后给各类组件注册合适的事件监听,比如mouse press listener,在listen响应处理中调用setfocus。
要提供setfocus指定某组件聚焦。Setfocus一旦成功返回,该组件将接受后继发生的所有的键盘事件,直到再次失去焦点。
然而问题是轻量级组件的容器是一个重量级组件,而在对轻量级组件调用setfocus时它的本地对等组件在系统中很可能还没有获得焦点。若实现上只是简单的把java的全局变量更新了,那系统就会出现两个聚焦组件:一个是底层系统承认的原来的某底层对等组件,一个是java里认为的现在的jtextfield。而本地系统始终把键盘事件派发到它认可的聚焦组件上,如果这个聚焦组件属于另外一个C++进程,那么这些键盘事件就会分发给C++进程,而不会被JVM的awt-windows loop到。也就是说,虽然setfocus成功返回了,但并不代表随后的键盘事件会target到这个组件上。所以不能采用这样的设计思路。
尽管如此,实际上我们的组件的监听一般是在mouse_press上。而这个鼠标按下动作各类底层操作系统处理时一般首先分发mouse_press底层事件,然后切换焦点,再分发focus事件。随后的键盘事件会在底层切换焦点后分发出去。假如我们确定下来所有GUI应用只在EDT线程在mouse_press监听处理中setfocus,实际上不会丢失键盘事件。但是如果我们要在其他情况,比如某worker 线程中setfocus,那么setfocus就不再可靠了。
那么,根据前面的分析,现在更改设计,在setfocus处理中调用底层API要求其重量级容器对应的本地对等组件聚焦并等到它确实聚焦完成了再更新JAVA的全局变量。但这样也有问题。即使底层系统根据底层调用通知更新了focus,马上还会继续对可能的焦点切换操作响应(可以认为有一个系统进程在处理外设的响应),很有可能别的C++应用就在此时再要求focus,于是接着就更新了底层的focus登记;而我们的setfocus调用却是在jvm进程的某线程中,显然这就是个并发的情景,这样,很有可能我们的对本地对等组件的通知发过去并返回了,那边底层系统就马上切换到了C++的某个组件focus,而我们的线程继续更新JAVA的全局focus变量,于是虽然setfocus成功返回了,但并不代表随后的键盘事件会target到这个组件上。
现在看来,除非我们同步这两个进程,让系统进程等待我们的调用setfocus的线程返回,显然那样是不合理的。(JAVA只能服从OS,不能让OS服从JAVA。---出自《英雄乱语》J)。
鉴于以上的分析,根本无法实现一个setfocus来完成一个切换焦点的原子性操作。jre1.7的实现为不存在setfocus,而只有requestfocus,意思是只是将这个切换焦点的请求登记上但并不进行实际切换focus;随后等收到相应的事件通知后再处理request并彻底完成一次focus切换。
2. 聚焦组件后马上获得随后的键盘事件。
难点是按用户的实际想法,mouse_press后,马上就要键盘拼写,键盘的输入应该target到mouse_press的jtextfield。根据前面的分析,mouse_press响应中requestfocus/setfocus后并没有意味着切换焦点已经完成。若实现上对于后续的键盘事件只是简单地根据JAVA的那个全局focus变量target,则这些键盘事件将不会target到期待的组件上。
鉴于以上的分析,jre1.7的实现是requestfocus时,只要这个请求满足必要条件,那么在其返回前就登记一个时间戳,在这个时间戳之后在下一个requestfocus时间戳之前,EDT 逐个取的keyevent都将target到该组件并登记,直到该组件彻底聚焦完成后,马上把这些keyevent dispatch。
3. 需要支持TAB键等焦点遍历操作。
这一点JAVA有一个遍历模型,如下:
具体参照http://java.sun.com/javase/6/docs/api/java/awt/doc-files/FocusSpec.html
该要 求并没有难点。实现上只要对keyevent监听,并根据规则进行合适处理即可。
分享到:
相关推荐
### 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"是一款基于Flash技术的幻灯片插件,主要用于创建动态、引人注目的图片展示。这款...
"focus.swf"即为一种实现焦点图切换功能的SWF文件,常用于广告展示或网站轮播图。本文将深入探讨focus.swf的图片切换原理、实现方式及其源代码分析。 1. **SWF文件简介** SWF全称为Small Web Format,是Adobe ...
本项目旨在通过Java、JSP和Servlet技术实现一个简单的用户登录系统。系统的核心功能包括用户登录验证、数据库连接及数据操作等。 #### 技术栈 - **前端**: HTML、JSP - **后端**: Servlet、JavaBean - **数据库**: ...
《用Java设计文本编辑器MiniEditor》是一款基于Java编程技术实现的轻量级文本编辑工具。这个项目旨在提供一个基础的文本编辑环境,允许用户进行基本的文字操作,如输入、复制、删除、选中、插入,以及查找和替换功能...
在移动端开发中, focus 事件是一个非常重要的事件,它可以帮助开发者更好地控制用户的输入行为。但是在iOS平台上,触发 focus 事件却是一个非常棘手的问题。本文将为大家分享解决iOS下无法触发focus事件的问题,并...
focus.swf 幻灯 简单 实用 <div id="index_focus"> [removed] swfobject.embedSWF("focus.... ,"icon":"图片1|图片2|图片3|图片4|图片5" } ,{ "allowFullScreen":"true" ,"wmode":"opaque" } ); [removed]
1. **库存管理系统**:在一个库存管理系统中,可能使用COBOL进行数据处理,而使用JAVA进行前端界面设计。通过JAVA调用COBOL中的库存管理逻辑,从而实现两者的协同工作。 2. **银行业务处理**:银行业务处理系统中,...
在Java编程语言中,构建定制的树型视图是一项常见的任务,特别是在开发用户界面或数据结构展示时。Java提供了一套强大的工具来帮助开发者创建这样的视图,这主要涉及到Java Swing库中的JTree组件。本篇文章将深入...
总结来说,Java 中实现带复选框的树(CheckBox Tree)需要自定义 TreeNode 类(CheckBoxTreeNode),用于存储结点是否被选中的状态,并实现选中/取消选中时子结点和父结点的状态更新。同时,还需要创建一个 ...
在这个实例中,我们主要探讨`JTable`的使用,以及如何在Java程序中实现一个基本的表格。 `JTable`通常配合`DefaultTableModel`使用,`DefaultTableModel`是`JTable`的数据模型,它负责存储和管理表格中的数据。创建...
为了处理焦点事件,我们需要实现`FocusListener`接口或者使用`addFocusListener()`方法添加一个已经实现该接口的对象。`FocusListener`接口包含以下四个方法: 1. `focusGained(FocusEvent e)`:焦点获得时调用。 2....
在Android系统中,AudioFocus是音频管理的一项重要特性,它允许应用程序之间协调音频播放,确保在特定场景下,如电话铃声、系统通知或者用户手动切换应用时,音频的播放能够顺畅且合理地进行切换。AudioFocus是...
WMC FOCUS6.3 用于风力发电叶片结构设计专用软件,此文档为其API 二次开发结构,采用Python语言进行二次开发
[奥莱理] 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实现系统目录树控件.txt"文档中,应该详细记录了实现这个功能的完整代码和可能遇到的问题及其解决方案。阅读并理解这个文档对于深入掌握Java目录树控件的实现至关重要。在实践中不断调整和优化,可以创建出更...