JAVA组件焦点的特性:其组件的顶层祖先必须为可见的。
requestFocus,requestFocusInWindow等这些方法在获取组件焦点时都提到了:
请求此 Component 获取输入焦点,并且此 Component 的顶层祖先成为获得焦点的 Window。此 Component 对于所要许可的请求而言
必须是不可显示的、可聚焦的和可见的并且其所有祖先(除了顶层 Window 以外)必须是可见的。此方法会尽力完成该请求;但是在某些情况下可能无法完成。在此 Component 接收 FOCUS_GAINED 事件前,开发人员永远不能假定此 Component 是焦点所有者。如果由于此 Component 的顶层 Window 没有成为获得焦点的窗口而拒绝了此请求,则记住此请求,并在后来用户使窗口成为获得焦点的窗口时许可此请求。
参考源码:Component的源码
Component window = this;
while ( (window != null) && !(window instanceof Window)) {
if (!window.isVisible()) {
if (focusLog.isLoggable(PlatformLogger.FINEST)) {
focusLog.finest("component is recurively invisible");
}
return false;
}
window = window.parent;
}
例子:
import java.awt.event.*;
import javax.swing.*;
public class two{
public static void main(String args[]){
final JFrame jf = new JFrame();
A a = new A();
jf.setSize(400,500);
jf.add(a);
jf.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_LEFT){
System.out.println("you");
}
}
});
a.requestFocus();
jf.setVisible(true);
jf.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e){
jf.requestFocus();
}
});
//a.requestFoucus();
}
}
class A extends JPanel{
public A() {
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_LEFT){
System.out.println("左");
}
}
});
}
}
代码简单说明:在two类中有一个窗体jf,对键盘事件监听,按下“←”,控制台打印出“you”,同时在Main方法中new出一个JPanel对象a,在类A中的构造方法中添加了键盘事件监听,按下“←”,控制台打印出“左”。同时为了实验,窗体jf实现了点击鼠标就会获得焦点。
实验一:a对象调用requestFocus()方法获得焦点后,窗体 jf 才显示。此时按下←键后,显示“you”。
实验二:窗体jf 先显示 再让a对象调用requestFocus()方法获得焦点。此时按下←键后,显示“左”。此时点击窗体,再按下←键后,显示“you”。
疑问:在实验一的情况下,如果点击JPanel所在处是否能获得JPanel的焦点呢?
窗体初始化时,此时焦点的拥有者为jf,(注释掉jf的监听鼠标事件后),点击JPanel的位置,测试结果仍为“you”。所以说明点击鼠标不能获得焦点。
结论:组件获取焦点时,其顶层容器必须可见。