如何使用 Focus 子系统
许多组件-甚至主要由鼠标操作的组件,例如按钮-都可以通过键盘进行操作。为了使按键受到影响,该组件必须具有键盘焦点。
从用户的角度来看,具有键盘焦点的组件通常很突出-例如带有虚线或黑色边框。包含该组件的窗口也比屏幕上的其他窗口突出。这些视觉提示使用户知道任何键入将与哪个组件相关。窗口系统中一次只能有一个组件具有键盘焦点。
窗口究竟如何获得焦点取决于窗口系统。在所有平台上,没有万无一失的方法来确保窗口获得焦点。在某些 os(例如 Microsoft Windows)上,前窗口通常成为焦点窗口。在这种情况下,Window.toFront方法将窗口移到最前面,从而使其成为焦点。但是,在其他 os(例如 Solaris™os)上,窗口 管理 器可能会根据光标位置选择聚焦窗口,在这种情况下,Window.toFront
方法的行为是不同的。
当用户单击某个组件时,或者当用户在组件之间进行制表或与组件进行交互时,组件通常会获得焦点。也可以通过编程方式给组件一个焦点,例如当使其包含的框架或对话框可见时。此代码段显示了每次窗口获得焦点时如何赋予特定组件焦点:
//Make textField get the focus whenever frame is activated.
frame.addWindowFocusListener(new WindowAdapter() {
public void windowGainedFocus(WindowEvent e) {
textField.requestFocusInWindow();
}
});
如果要确保特定组件在第一次激活窗口时获得焦点,则可以在实现该组件之后但在显示框架之前在该组件上调用requestFocusInWindow方法。以下示例代码显示了如何完成此操作:
//...Where initialization occurs...
JFrame frame = new JFrame("Test");
JPanel panel = new JPanel(new BorderLayout());
//...Create a variety of components here...
//Create the component that will have the initial focus.
JButton button = new JButton("I am first");
panel.add(button);
frame.getContentPane().add(panel); //Add it to the panel
frame.pack(); //Realize the components.
//This button will have the initial focus.
button.requestFocusInWindow();
frame.setVisible(true); //Display the window.
或者,您可以将自定义FocusTraversalPolicy
应用于框架并调用getDefaultComponent
方法以确定哪个组件将获得焦点。
本节的其余部分包括以下主题:
Focus 子系统简介
焦点子系统旨在尽可能不可见地做正确的事情。在大多数情况下,它以合理的方式运行,如果不运行,则可以通过各种方式调整其行为。一些常见的情况可能包括:
-
Sequences 正确,但未设置焦点所在的第一个组件。如上一节中的代码片段所示,当窗口变为可见时,可以使用
requestFocusInWindow
方法将焦点设置在组件上。 -
Order 错误。要解决此问题,您可以更改容纳层次结构,可以更改组件添加到其容器的 Sequences,也可以创建自定义焦点遍历策略。有关更多详细信息,请参见自定义焦点遍历。
-
必须防止组件失去焦点,或者您需要在失去焦点之前检查组件中的值。 Input verification是解决此问题的方法。
-
自定义组件无法获得焦点。要解决此问题,您需要确保它满足使自定义组件具有焦点中概述的所有要求。
FocusConceptsDemo
示例说明了一些概念。
Try this:
-
单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 FocusConceptsDemo。另外,要自己编译和运行示例,请查阅example index。
-
如有必要,请单击窗口以使其成为焦点。
-
使用 Tab 键将焦点从一个组件移到另一个组件。
您会注意到,当焦点移到文本区域时,它将停留在文本区域中。 -
使用 Control-Tab 将焦点移到文本区域之外。
-
使用 Shift-Tab 键向相反方向移动焦点。
-
使用 Control-Shift-Tab 键将焦点沿相反方向移出文本区域。
KeyboardFocusManager
是焦点子系统的关键元素。它 管理 状态并启动更改。键盘 管理 器跟踪焦点所有者-从键盘接收键入的组件。焦点窗口是包含焦点所有者的窗口。
JWindow and focus:
焦点循环(或焦点遍历循环)是在包含层次结构中共享共同祖先的一组组件。焦点循环根是容器,它是特定焦点遍历循环的根。默认情况下,每个JWindow
和JInternalFrame
组件都可以是焦点循环的根。聚焦循环根本身可以包含一个或多个聚焦循环根。以下 Swing 对象可以是焦点循环的根:JApplet
,JDesktopPane
,JDialog
,JEditorPane
,JFrame
,JInternalFrame
和JWindow
。尽管JTable
和JTree
对象似乎是聚焦循环的根,但它们不是。
焦点遍历策略确定一组组件的导航 Sequences。 Swing 提供了LayoutFocusTraversalPolicy类,该类根据与布局 管理 器相关的因素(例如组件的大小,位置和方向)确定导航 Sequences。在一个聚焦周期内,组件可以向前或向后导航。在焦点循环根的层次结构中,向上遍历会将焦点从当前循环移到父循环中。
在大多数外观模型中,使用 Tab 和 Shift-Tab 键浏览组件。这些键是默认的焦点遍历键,可以通过编程更改。例如,您可以使用以下四行代码将 Enter 添加为前向遍历键:
Set forwardKeys = getFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
Set newForwardKeys = new HashSet(forwardKeys);
newForwardKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
newForwardKeys);
Tab 可以将焦点向前移动。 Shift-Tab 键可将焦点向后移动。例如,在 FocusConceptsDemo 中,第一个按钮具有初始焦点。 Tab 键将焦点通过按钮移动到文本区域。额外的制表符会将光标移动到文本区域内,但不能移出文本区域,因为在文本区域内,Tab 不是焦点遍历键。但是,Control-Tab 键可将焦点移出文本区域并移至第一个文本字段。同样,Control-Shift-Tab 键可将焦点移出文本区域并移至上一个组件。按照惯例,使用 Control 键将焦点移出以特殊方式处理 Tab 的任何组件,例如JTable
。
您刚刚收到了有关焦点体系结构的简短介绍。如果需要更多详细信息,请参见Focus Subsystem的规范。
Validating Input
GUI 设计的一个常见要求是限制用户 Importing 的组件,例如,一个文本字段仅允许使用十进制格式的数字 Importing(例如,钱),或者一个文本字段仅允许 5 位邮政编码。易于使用的格式化文本字段组件,可将 Importing 限制为各种可本地化的格式。您还可以为文本字段指定custom formatter,它可以执行特殊检查,例如确定值是否不仅格式正确,而且合理。
您可以使用 Importing 验证程序来替代自定义格式程序,或者当您使用的组件不是文本字段时。Importing 验证程序允许您拒绝特定值,例如格式正确但无效的邮政编码,或超出所需范围的值,例如体温高于 110°F。要使用 Importing 验证器,请创建一个InputVerifier的子类,创建该子类的实例,然后将该实例设置为一个或多个组件的 Importing 验证器。
每当组件即将失去焦点时,都会咨询组件的 Importing 验证程序。如果组件的值不可接受,则 Importing 验证程序可以采取适当的措施,例如拒绝将注意力集中在组件上,或者将用户的 Importing 替换为最后一个有效值,然后将焦点转移到下一个组件。但是,将焦点转移到另一个顶级组件时,不会调用InputVerifier
。
下面的两个示例显示抵押计算器。一种使用格式化的文本字段,另一种使用标准文本字段的 Importing 验证。
Try this:
-
单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 FormattedTextFieldDemo。另外,要自己编译和运行示例,请查阅example index。
-
单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 InputVerificationDemo。另外,要自己编译和运行示例,请查阅example index。
-
并排比较两个抵押计算器。您将看到 Importing 验证演示在关联的标签中为每个可编辑文本字段指定了有效的 Importing 值。try在两个示例中 Importing 格式错误的值,以观察行为。然后try Importing 格式正确但不可接受的值。
您可以在InputVerificationDemo.java中找到 Input Verification 演示的代码。这是InputVerifier
子类MyVerifier
的代码:
class MyVerifier extends InputVerifier
implements ActionListener {
double MIN_AMOUNT = 10000.0;
double MAX_AMOUNT = 10000000.0;
double MIN_RATE = 0.0;
int MIN_PERIOD = 1;
int MAX_PERIOD = 40;
public boolean shouldYieldFocus(JComponent input) {
boolean inputOK = verify(input);
makeItPretty(input);
updatePayment();
if (inputOK) {
return true;
} else {
Toolkit.getDefaultToolkit().beep();
return false;
}
}
protected void updatePayment() {
double amount = DEFAULT_AMOUNT;
double rate = DEFAULT_RATE;
int numPeriods = DEFAULT_PERIOD;
double payment = 0.0;
//Parse the values.
try {
amount = moneyFormat.parse(amountField.getText()).
doubleValue();
} catch (ParseException pe) {pe.printStackTrace();}
try {
rate = percentFormat.parse(rateField.getText()).
doubleValue();
} catch (ParseException pe) {pe.printStackTrace();}
try {
numPeriods = decimalFormat.parse(numPeriodsField.getText()).
intValue();
} catch (ParseException pe) {pe.printStackTrace();}
//Calculate the result and update the GUI.
payment = computePayment(amount, rate, numPeriods);
paymentField.setText(paymentFormat.format(payment));
}
//This method checks input, but should cause no side effects.
public boolean verify(JComponent input) {
return checkField(input, false);
}
protected void makeItPretty(JComponent input) {
checkField(input, true);
}
protected boolean checkField(JComponent input, boolean changeIt) {
if (input == amountField) {
return checkAmountField(changeIt);
} else if (input == rateField) {
return checkRateField(changeIt);
} else if (input == numPeriodsField) {
return checkNumPeriodsField(changeIt);
} else {
return true; //should not happen
}
}
//Checks that the amount field is valid. If it is valid,
//it returns true; otherwise, returns false. If the
//change argument is true, this method sets the
//value to the minimum or maximum value if necessary and
// (even if not) sets it to the parsed number so that it
// looks good -- no letters, for example.
protected boolean checkAmountField(boolean change) {
boolean wasValid = true;
double amount = DEFAULT_AMOUNT;
//Parse the value.
try {
amount = moneyFormat.parse(amountField.getText()).
doubleValue();
} catch (ParseException pe) {
pe.printStackTrace();
wasValid = false;
}
//Value was invalid.
if ((amount < MIN_AMOUNT) || (amount > MAX_AMOUNT)) {
wasValid = false;
if (change) {
if (amount < MIN_AMOUNT) {
amount = MIN_AMOUNT;
} else { // amount is greater than MAX_AMOUNT
amount = MAX_AMOUNT;
}
}
}
//Whether value was valid or not, format it nicely.
if (change) {
amountField.setText(moneyFormat.format(amount));
amountField.selectAll();
}
return wasValid;
}
//Checks that the rate field is valid. If it is valid,
//it returns true; otherwise, returns false. If the
//change argument is true, this method reigns in the
//value if necessary and (even if not) sets it to the
//parsed number so that it looks good -- no letters,
//for example.
protected boolean checkRateField(boolean change) {
...//Similar to checkAmountField...
}
//Checks that the numPeriods field is valid. If it is valid,
//it returns true; otherwise, returns false. If the
//change argument is true, this method reigns in the
//value if necessary and (even if not) sets it to the
//parsed number so that it looks good -- no letters,
//for example.
protected boolean checkNumPeriodsField(boolean change) {
...//Similar to checkAmountField...
}
public void actionPerformed(ActionEvent e) {
JTextField source = (JTextField)e.getSource();
shouldYieldFocus(source); //ignore return value
source.selectAll();
}
}
请注意,实现verify
方法是为了检测无效值,但不会执行其他任何操作。 verify
方法仅用于确定 Importing 是否有效-绝不应该弹出对话框或引起任何其他副作用。 shouldYieldFocus
方法调用verify
,如果值无效,则将其设置为最小值或最大值。允许shouldYieldFocus
方法引起副作用,在这种情况下,它总是格式化文本字段,并且还可能更改其值。在我们的示例中,shouldYieldFocus
方法始终返回 true,因此实际上不会阻止焦点的转移。这只是可以执行验证的一种方式。查找该演示的另一个版本InputVerificationDialogDemo,当用户 Importing 无效并要求用户 Importing 合法值时,该对话框会弹出一个对话框。
Importing 验证程序是使用JComponent
类的setInputVerifier
方法安装的。例如,InputVerificationDemo
具有以下代码:
private MyVerifier verifier = new MyVerifier();
...
amountField.setInputVerifier(verifier);
使自定义组件具有焦点
为了使组件获得焦点,它必须满足三个要求:它必须是可见的,启用的和可聚焦的。也可以给出 Importing 图。有关 ImportingMap 的更多信息,请阅读如何使用键绑定。
TrackFocusDemo示例定义了简单组件Picture
。其构造函数如下所示:
public Picture(Image image) {
this.image = image;
setFocusable(true);
addMouseListener(this);
addFocusListener(this);
}
对setFocusable(true)
方法的调用使该组件具有焦点。如果您在其WHEN_FOCUSED
ImportingMap 中显式提供了组件键绑定,则无需调用setFocusable
方法。
为了直观地显示焦点的变化(仅当组件具有焦点时才绘制红色边框),Picture
具有focus listener。
为了在用户单击图片时获得焦点,组件具有mouse listener。侦听器的mouseClicked
方法请求将焦点转移到图片上。这是代码:
public void mouseClicked(MouseEvent e) {
//Since the user clicked on us, let us get focus!
requestFocusInWindow();
}
有关 TrackFocusDemo 示例的更多讨论,请参见跟踪焦点更改到多个组件。
自定义焦点遍历
焦点子系统确定使用焦点遍历键(例如 Tab)进行导航时所应用的默认 Sequences。 Swing 应用程序的策略由LayoutFocusTraversalPolicy确定。您可以使用setFocusCycleRoot方法在任何Container
上设置焦点遍历策略。但是,如果容器不是焦点循环的根,则可能没有明显的作用。或者,您可以将焦点遍历策略提供程序传递给FocusTraversalPolicy
方法,而不是焦点循环根。使用isFocusTraversalPolicyProvider()方法来确定Container
是否是焦点遍历策略提供者。使用setFocusTraversalPolicyProvider()方法来设置用于提供焦点遍历策略的容器。
FocusTraversalDemo
示例演示了如何自定义焦点行为。
Try this:
-
单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 FocusTraversalDemo。另外,要自己编译和运行示例,请查阅example index。
-
如有必要,请单击窗口以使其成为焦点。
-
当您浏览组件时,请注意焦点 Sequences。焦点 Sequences 由组件添加到内容窗格的 Sequences 确定。还请注意,复选框永远不会获得焦点;我们从焦点周期中将其删除。
-
要将焦点移到表外,请使用 Control-Tab 或 Control-Shift-Tab。
-
单击“自定义 FocusTraversalPolicy”复选框。此框在框架上安装自定义焦点遍历策略。
-
try再次浏览各个组件。请注意,现在焦点 Sequences 是从左到右,从上到下的 Sequences。
您可以在FocusTraversalDemo.java中找到该演示的代码。
使用以下代码行将代码从焦点循环中删除:
togglePolicy.setFocusable(false);
这是应用程序的自定义FocusTraversalPolicy
:
...
JTextField tf1 = new JTextField("Field 1");
JTextField tf2 = new JTextField("A Bigger Field 2");
JTextField tf3 = new JTextField("Field 3");
JTextField tf4 = new JTextField("A Bigger Field 4");
JTextField tf5 = new JTextField("Field 5");
JTextField tf6 = new JTextField("A Bigger Field 6");
JTable table = new JTable(4,3);
...
public FocusTraversalDemo() {
super(new BorderLayout());
JTextField tf1 = new JTextField("Field 1");
JTextField tf2 = new JTextField("A Bigger Field 2");
JTextField tf3 = new JTextField("Field 3");
JTextField tf4 = new JTextField("A Bigger Field 4");
JTextField tf5 = new JTextField("Field 5");
JTextField tf6 = new JTextField("A Bigger Field 6");
JTable table = new JTable(4,3);
togglePolicy = new JCheckBox("Custom FocusTraversalPolicy");
togglePolicy.setActionCommand("toggle");
togglePolicy.addActionListener(this);
togglePolicy.setFocusable(false); //Remove it from the focus cycle.
//Note that HTML is allowed and will break this run of text
//across two lines.
label = new JLabel("<html>Use Tab (or Shift-Tab) to navigate from component to component.<p>Control-Tab
(or Control-Shift-Tab) allows you to break out of the JTable.</html>");
JPanel leftTextPanel = new JPanel(new GridLayout(3,2));
leftTextPanel.add(tf1, BorderLayout.PAGE_START);
leftTextPanel.add(tf3, BorderLayout.CENTER);
leftTextPanel.add(tf5, BorderLayout.PAGE_END);
leftTextPanel.setBorder(BorderFactory.createEmptyBorder(0,0,5,5));
JPanel rightTextPanel = new JPanel(new GridLayout(3,2));
rightTextPanel.add(tf2, BorderLayout.PAGE_START);
rightTextPanel.add(tf4, BorderLayout.CENTER);
rightTextPanel.add(tf6, BorderLayout.PAGE_END);
rightTextPanel.setBorder(BorderFactory.createEmptyBorder(0,0,5,5));
JPanel tablePanel = new JPanel(new GridLayout(0,1));
tablePanel.add(table, BorderLayout.CENTER);
tablePanel.setBorder(BorderFactory.createEtchedBorder());
JPanel bottomPanel = new JPanel(new GridLayout(2,1));
bottomPanel.add(togglePolicy, BorderLayout.PAGE_START);
bottomPanel.add(label, BorderLayout.PAGE_END);
add(leftTextPanel, BorderLayout.LINE_START);
add(rightTextPanel, BorderLayout.CENTER);
add(tablePanel, BorderLayout.LINE_END);
add(bottomPanel, BorderLayout.PAGE_END);
setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
Vector<Component> order = new Vector<Component>(7);
order.add(tf1);
order.add(tf2);
order.add(tf3);
order.add(tf4);
order.add(tf5);
order.add(tf6);
order.add(table);
newPolicy = new MyOwnFocusTraversalPolicy(order);
}
要使用自定义FocusTraversalPolicy
,请在任何焦点循环根目录上实现以下代码。
MyOwnFocusTraversalPolicy newPolicy = new MyOwnFocusTraversalPolicy();
frame.setFocusTraversalPolicy(newPolicy);
您可以通过将FocusTraversalPolicy
设置为null
来删除自定义焦点遍历策略,这将恢复默认策略。
跟踪焦点到多个组件的更改
在某些情况下,应用程序可能需要跟踪哪个组件具有焦点。此信息可能用于动态更新菜单或状态栏。如果您只需要关注特定组件,则可以实现焦点事件监听器。
如果焦点监听器不合适,则可以在KeyboardFocusManager
上注册PropertyChangeListener
。向属性更改侦听器通知涉及焦点的每个更改,包括对焦点所有者,焦点窗口和默认焦点遍历策略的更改。有关完整列表,请参见KeyboardFocusManager Properties表。
The以下示例演示如何通过在键盘焦点 管理 器上安装属性更改侦听器来跟踪焦点所有者。
Try this:
-
单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 TrackFocusDemo。另外,要自己编译和运行示例,请查阅example index。
-
如有必要,请单击窗口以使其成为焦点。
-
该窗口显示六个图像,每个图像由
Picture
组件显示。具有焦点的Picture
带有红色边框。窗口底部的标签描述了具有焦点的Picture
。 -
通过使用 Tab 或 Shift-Tab 或单击图像,将焦点移至另一个
Picture
。因为属性更改侦听器已在键盘焦点 管理 器上注册,所以可以检测到焦点更改并适当地更新标签。
您可以在TrackFocusDemo.java中查看演示的代码。用于绘制图像的自定义组件可以在Picture.java中找到。以下是定义和安装属性更改侦听器的代码:
KeyboardFocusManager focusManager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (("focusOwner".equals(prop)) &&
((e.getNewValue()) instanceof Picture)) {
Component comp = (Component)e.getNewValue();
String name = comp.getName();
Integer num = new Integer(name);
int index = num.intValue();
if (index < 0 || index > comments.length) {
index = 0;
}
info.setText(comments[index]);
}
}
}
);
定制组件Picture
负责绘制图像。通过以下方式定义所有六个组件:
pic1 = new Picture(createImageIcon("images/" +
mayaString + ".gif", mayaString).getImage());
pic1.setName("1");
时间重点转移
焦点转移是异步的。这种质量可能会导致一些与计时相关的奇怪问题和假设,尤其是在焦点自动转移期间。例如,假设一个应用程序具有一个包含“开始”按钮,“取消”按钮和文本字段的窗口。组件按以下 Sequences 添加:
-
Start button
-
Text field
-
Cancel button
启动应用程序时,LayoutFocusTraversalPolicy
确定焦点遍历策略-在这种情况下,这是将组件添加到其容器的 Sequences。在此示例中,所需的行为是“开始”按钮具有初始焦点,并且在单击“开始”按钮时将其禁用,然后“取消”按钮获得了焦点。实现此行为的正确方法是按照所需 Sequences 将组件添加到容器中,或者创建自定义焦点遍历策略。如果由于某种原因无法执行此操作,则可以使用以下代码段实现此行为:
public void actionPerformed(ActionEvent e) {
//This works.
start.setEnabled(false);
cancel.requestFocusInWindow();
}
根据需要,焦点从“开始”按钮转到“取消”按钮,而不是文本字段。但是,如果以相反的 Sequences 调用相同的方法,则会产生不同的结果,如下所示:
public void actionPerformed(ActionEvent e) {
//This does not work.
cancel.requestFocusInWindow();
start.setEnabled(false);
}
在这种情况下,焦点在离开“开始”按钮之前就需要在“取消”按钮上进行。调用requestFocusInWindow
方法会启动焦点转移,但是不会立即将焦点移到“取消”按钮。当“开始”按钮被禁用时,焦点将转移到下一个组件(因此始终有焦点的组件),在这种情况下,它将把焦点移动到文本字段,而不是“取消”按钮。
在可能影响焦点的所有其他更改应用于以下情况后,需要在几种情况下发出焦点请求:
-
隐藏焦点所有者。
-
使焦点所有者无法聚焦。
-
在焦点所有者上调用
removeNotify
方法。 -
对焦点所有者的容器执行上述任何操作,或对焦点策略进行更改,以使容器不再接受该组件作为焦点所有者。
-
处理包含焦点所有者的顶层窗口。
Focus API
下表列出了与焦点相关的常用构造函数和方法。焦点 API 分为四类:
有关焦点体系结构的更多详细信息,请参见Focus Subsystem的规范。您可能还会发现如何编写焦点侦听器有用。
方法(在Component 中) | Purpose |
---|---|
isFocusOwner() | 如果组件是焦点所有者,则返回true 。 |
setRequestFocusEnabled(boolean) | |
isRequestFocusEnabled() (* in JComponent )* | 设置或检查此组件是否应获得焦点。将setRequestFocusEnabled 设置为false 通常可以防止鼠标单击为组件提供焦点,同时仍允许键盘导航为组件提供焦点。此方法仅适用于接收鼠标事件的组件。例如,可以在JButton 上使用此方法,但不能在JPanel 上使用。如果编写自定义组件,则由您决定是否使用此属性。与setFocusable 方法相比,建议使用此方法,它将使您的程序对于使用assistive technologies的用户更好地工作。 |
setFocusable(boolean) isFocusable() | 设置或获取组件的可聚焦状态。组件必须是可聚焦的才能获得焦点。使用setFocusable(false) 从焦点循环中删除某个组件后,将无法再使用键盘进行导航。建议使用setRequestFocusEnabled 方法,以便使用assistive technologies的用户可以运行您的程序。 |
requestFocusInWindow() | 请求此组件应获得焦点。组件的窗口必须是当前的焦点窗口。为使此请求被授予,JComponent 的子类必须是可见的,启用的和可聚焦的,并且具有要授予该请求的 ImportingMap。在触发FOCUS_GAINED 事件之前,不应假定组件具有焦点。该方法优于requestFocus 方法,后者取决于平台。 |
setFocusTraversalKeys(int, Set) getFocusTraversalKeys(int) areFocusTraversalKeysSet(int) (* in java.awt.Container *) | 设置或获取特定方向的焦点遍历键,或确定是否已在此容器上显式设置任何焦点遍历键。如果未设置焦点遍历键,则它们是从祖先或键盘焦点 管理 器继承的。可以将焦点遍历键设置为以下方向:KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS ,KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS 或KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS 。如果设置UP_CYCLE_TRAVERSAL_KEYS 或DOWN_CYCLE_TRAVERSAL_KEYS ,则还必须在焦点遍历策略上调用setImplicitDownCycleTraversal(false)。 |
类或方法 | Purpose |
---|---|
LayoutFocusTraversalPolicy | 默认情况下,该类确定 Swing 组件的焦点遍历策略。 |
getComponentAfter(Container, Component) | 给定作为 Importing 传递的组件,返回接下来应该具有焦点的组件。 |
getComponentBefore(Container, Component) | 给定作为 Importing 传递的组件,返回在该组件之前应具有焦点的组件。该方法用于后退制表。 |
getDefaultComponent(Container) | |
(在 javax.swing.SortingFocusTraversalPolicy 中) | 返回应具有默认焦点的组件。 |
getFirstComponent(Container) | 返回遍历循环中的第一部分。 |
getInitialComponent(Container) | 返回第一次使窗口可见时应获得焦点的组件。 |
getLastComponent(Container) | 返回遍历循环中的最后一个分量。 |
setFocusTraversalPolicy(FocusTraversalPolicy) getFocusTraversalPolicy(FocusTraversalPolicy) (* in java.awt.Container *) | 设置或获取焦点遍历策略,或确定是否已设置策略。请注意,在不是焦点循环根的容器上设置焦点遍历策略可能没有明显效果。值null 表示尚未显式设置策略。如果未设置策略,则从父焦点循环根继承策略。 |
isFocusCycleRoot() setFocusCycleRoot(boolean) (*在 java.awt.Container *中) | 检查或设置容器是否为焦点遍历循环的根。 |
isFocusTraversalPolicyProvider() setFocusTraversalPolicyProvider(boolean) (*在 java.awt.Container *中) | 检查或设置是否使用容器提供焦点遍历策略。 |
类或方法 | Purpose | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
InputVerifier | 允许通过焦点机制进行 Importing 验证的抽象类。try将焦点从包含 Importing 验证程序的组件上移开时,直到满足验证程序,才会放弃焦点。 | ||||||||||||||||||||||||||||||||
shouldYieldFocus(JComponent) | |||||||||||||||||||||||||||||||||
(在 InputVerifier 中) | 当组件具有 Importing 验证程序时,系统将调用此方法以确定焦点是否可以离开此组件。此方法可能会导致副作用,例如弹出对话框。如果此方法返回false ,则焦点将停留在传递给该方法的组件上。 | ||||||||||||||||||||||||||||||||
verify(JComponent) (在 InputVerifier 中) | 您需要重写此方法以检查组件的 Importing 是否有效。如果有效,它将返回true ,否则返回false 。此方法不应引起任何副作用,例如弹出对话框。此方法由shouldYieldFocus 调用。 | ||||||||||||||||||||||||||||||||
setInputVerifier(inputVerifier) getInputVerifier() (在 JComponent 中) | 设置或获取分配给组件的 Importing 验证程序。默认情况下,组件没有 Importing 验证程序。 | ||||||||||||||||||||||||||||||||
setVerifyInputWhenFocusTarget(boolean) getVerifyInputWhenFocusTarget() (在 JComponent 中) | 设置或获取是否在此组件请求焦点之前调用当前焦点所有者的 Importing 验证程序。默认值为true 。 |
KeyboardFocusManager Properties
该表定义了KeyboardFocusManager的绑定属性。可以通过调用addPropertyChangeListener为这些属性注册一个侦听器。
Property | Purpose |
---|---|
focusOwner | 当前接收关键事件的组件。 |
permanentFocusOwner | 最近收到永久FOCUS_GAINED 事件的组件。通常与focusOwner 相同,除非当前正在进行临时焦点更改。 |
focusedWindow | 是或包含焦点所有者的窗口。 |
activeWindow | 组件必须始终为Frame 或Dialog 。活动窗口可以是焦点窗口,也可以是焦点窗口的所有者的第一帧或对话框。 |
defaultFocusTraversalPolicy | 默认的焦点遍历策略,可以通过Container 类的setFocusTraversalPolicy 方法设置。 |
forwardDefaultFocusTraversalKeys | 向前遍历的默认焦点键集。对于多行文本组件,这些键默认为 Control-Tab。对于所有其他组件,这些键默认为 Tab 和 Control-Tab。 |
backwardDefaultFocusTraversalKeys | 向后遍历的默认焦点键集。对于多行文本组件,这些键默认为 Control-Shift-Tab。对于所有其他组件,这些键默认为 Shift-Tab 和 Control-Shift-Tab。 |
upCycleDefaultFocusTraversalKeys | 向上循环的默认聚焦键集。对于 Swing 组件,这些键默认为 null。如果将这些键设置在KeyboardFocusManager 上,或者将downCycleFocusTraversalKeys 设置在焦点循环根目录上,则还必须在焦点遍历策略上调用setImplicitDownCycleTraversal(false)方法。 |
downCycleDefaultFocusTraversalKeys | 向下循环的默认聚焦键集。对于 Swing 组件,这些键默认为 null。如果将这些键设置在KeyboardFocusManager 上,或者将upCycleFocusTraversalKeys 设置在焦点循环根目录上,则还必须在焦点遍历策略上调用setImplicitDownCycleTraversal(false)方法。 |
currentFocusCycleRoot | 当前焦点周期根的容器。 |
使用焦点的示例
下表列出了操纵焦点的示例:
Example | Where Described | Notes |
---|---|---|
FocusConceptsDemo | This section | 演示基本的默认焦点行为。 |
FocusTraversalDemo | This section | 演示如何覆盖默认的焦点 Sequences。 |
TrackFocusDemo | This section | 演示如何使用PropertyChangeListener 跟踪焦点所有者。还实现自定义可聚焦组件。 |
InputVerificationDemo | This section | 演示如何实现InputVerifier 来验证用户 Importing。 |
InputVerificationDialogDemo | This section | 演示如何实现当用户 Importing 无效时创建一个对话框的InputVerifier 。 |
FocusEventDemo | 如何编写焦点侦听器 | 报告发生在多个组件上的所有焦点事件,以演示触发焦点事件的情况。 |