swing录入框被两个面板共用时的焦点问题

原始发表时间:2009-07-21

 

开发环境:
JDK 1.6.0
Eclilpse 3.3.2

    明天号称N百年一次的日全食~~可是XM这边只能看到偏食~~芹菜吧~~今晚还是照例加班,花N个钟头解决一个头疼的焦点问题,有效代码只有一行。

    用swing写程序是越来越痛苦了,先是组合框的选项列表不能根据选项文本的长度来自动调节宽度(查阅官方的bug列表,从2002年就有人提出,而且很不幸的是直到今天,这还是一个bug……),后是今天的焦点控制系统跟操作系统隔膜的有来有去。前者不提,本文只说后者是在什么工作场景下遭遇的——

    项目中需要根据配置动态生成一个表格和编辑界面,表格中各列的单元格编辑器是动态生成的,有可能是文本框或下拉框,双击某个单元格后,从表格切换到编辑界面。表格中显示大量的人员信息,双击某个单元格,则在编辑页中显示该行数据的具体内容。

    因为两个界面中编辑器相同,所以复用它们。

    双击表格中人员信息的“姓名”列,进入编辑界面,而后一直按TAB键切换焦点,挨个遍历各个录入框,因为顺序不确定,焦点有可能会在遍历到某个编辑器时,切换到编辑页外的其他组件。参考了Java官方教程里关于焦点子系统的教程,继承实现了自己的焦点转换策略。将所有的编辑器按照预期的顺序串联起来。

    但是发现另外一个问题,当焦点切换到“姓名”录入框时,按TAB键会发现焦点又返回到第一个录入框。

    起初猜测是整个切换过程是在双击表格中“姓名”列的事件处理逻辑触发的,而处理双击事件的时候,“姓名”列的单元格编辑器仍然具有焦点。这个单元格编辑器与编辑页中的“姓名”录入框共用了同一个文本框对象。但是为什么会影响到焦点切换,仍没有头绪。

    后来想到既然是切换焦点时从“姓名”录入框跳回到第一个录入框,那么也就肯定是焦点切换策略中 getComponentAfter(...) 方法无法正确获取下一个组件,而错误地得到第一个组件。于是用老一套方法,在自己实现的代码中 getComponentAfter(...) 方法第一行设置断点,观察调用堆栈中最有可能出现问题的地方,最终聚焦到类 LegacyGlueFocusTraversalPolicy 的方法 Component getComponentAfter(Container focusCycleRoot, Component aComponent) 上,单步前进发现判断语句

    delegatePolicy != null && prevHardCoded.isFocusCycleRoot(focusCycleRoot)

    无法返回true,也就导致无法正常调用我自己编写的焦点转换策略中的方法 getComponentAfter(...)

    但是 delegatePolicy 肯定不为null,也即是说后一个条件返回了false;当焦点放在“姓名”编辑框上是,prevHardCoded正是录入“姓名”的文本框对象,方法 isFocusCycleRoot(...) 正是用来判断组件是否为某个面板的焦点循环系统中的一员。结果很不幸,貌似(请注意这里用了“貌似”,因为我没有找到佐证的代码,所以只能猜测)“姓名”编辑框已经被先作为表格的单元格编辑器对象,所以无法不能算是编辑页面板的焦点循环系统中的一员,这也能解释为什么方法 isFocusCycleRoot(...) 返回false了。

    查阅网上一帖子的解决方法是覆写 JTextField 的方法 isFocusCycleRoot(...),始终返回true。不过我很困扰随便覆写这种方法的做法,于是乎尝试了一下在这个录入框初始化的时候,设置属性 focusCycleRoot 为 true,结果竟然可行,表格和编辑页的焦点循环系统都能够正常的在录入框上转移焦点了~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值