Java 检测具有多个子组件的focuslost
我想创建一个可扩展的面板(为特定任务容纳多个UI元素)。面板可以通过用户操作展开,只要面板中的任何子组件都有焦点,面板就应该保持展开状态。当用户将焦点放在面板外某个位置时,它应该关闭 有简单的方法吗Java 检测具有多个子组件的focuslost,java,swing,user-interface,focus,Java,Swing,User Interface,Focus,我想创建一个可扩展的面板(为特定任务容纳多个UI元素)。面板可以通过用户操作展开,只要面板中的任何子组件都有焦点,面板就应该保持展开状态。当用户将焦点放在面板外某个位置时,它应该关闭 有简单的方法吗 当焦点移出任何子组件时,获取focuslost事件 或者询问面板的任何子组件是否仍然具有焦点 或者我需要在每个子组件上注册/检查焦点(-events)? (因为这应该是一个通用的面板,我需要一种独立于子组件特定层次结构的通用方法。)根据,是在当前的KeyboardFocusManager上安装一
- 当焦点移出任何子组件时,获取focuslost事件
- 或者询问面板的任何子组件是否仍然具有焦点
(因为这应该是一个通用的面板,我需要一种独立于子组件特定层次结构的通用方法。)根据,是在当前的
KeyboardFocusManager
上安装一个PropertyChangeListener
。例如:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Main {
private static void createAndShowGUI() {
final int rows = 5, cols = 5;
final JPanel focusables = new JPanel(new GridLayout(0, cols, 10, 10));
for (int row = 0; row < rows; ++row)
for (int col = 0; col < cols; ++col)
focusables.add(new JTextField("Focusable", 10));
final JPanel nonFocusable = new JPanel(); //FlowLayout.
nonFocusable.add(new JTextField("Click here to change focus"));
final JPanel contents = new JPanel(new BorderLayout());
contents.add(focusables, BorderLayout.CENTER);
contents.add(nonFocusable, BorderLayout.LINE_END);
KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("focusOwner", new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent evt) {
final Object newValue = evt.getNewValue();
if (newValue instanceof Component
&& SwingUtilities.isDescendingFrom((Component) newValue, focusables)) //If 'focusables' is a parent of newValue...
focusables.setBackground(Color.GREEN); //Then focus is back on our components...
else
focusables.setBackground(Color.RED); //Else the focus is not on our components (it may even be another application).
}
});
final JFrame frame = new JFrame("Multi focus lost");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(contents);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(Main::createAndShowGUI);
}
}
导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.Component;
导入java.awt.GridLayout;
导入java.awt.KeyboardFocusManager;
导入java.beans.PropertyChangeEvent;
导入java.beans.PropertyChangeListener;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.JTextField;
导入javax.swing.SwingUtilities;
公共班机{
私有静态void createAndShowGUI(){
最终int行=5,cols=5;
最终JPanel焦点值=新JPanel(新网格布局(0,cols,10,10));
对于(int行=0;行<行;++行)
for(int col=0;col
根据教程:
每次涉及焦点的更改都会通知属性更改侦听器
如何使用上述示例:
JTextField
中单击以获得焦点JTextField
具有我们指定的父组件(在本例中,该组件是所需JTextField
s的父JPanel
,名为focusables
),则该父项的背景色变为绿色,否则为红色。但是你显然可以实现你的逻辑,而不是改变背景颜色
KeyboardFocusManager
上为属性focusOwner
安装PropertyChangeListener
,只有当应用程序中的任何组件更改其focusOwner属性时(即更改聚焦的组件
触发此类事件),我们才会收到通知。我们可以安装一个PropertyChangeListener
,这样我们就可以得到各种事件的通知,但是focusOwner
是我们唯一感兴趣的,所以我们会让系统知道。有关可按焦点事件跟踪的所有属性的列表,请滚动至
PropertyChangeListener
实现中,我们只需要检查新的焦点所有者是否具有其父级的focusables
面板。我们可以通过从焦点所有者向上遍历组件
层次结构来检查这一点,或者只需调用SwingUtilities#isdescingdrom
,这是一种方便的方法。如果我们正在侦听所有焦点事件,那么我们还必须手动筛选属性focusOwner
(通过检查propertychangevent#getPropertyName
返回该属性)组件的焦点会丢失(但当我们返回时会返回)
还要注意的是,为了简单起见,组件
s在上述示例中的层次结构仅为一级深度(即所需的可聚焦组件
s是可聚焦
面板的直接子级),但我们可以将其更改为我们想要的任何级别深度,只要所需的组件
s在其路径上都具有相同的父级(必须与非所需组件的父级不同)
我能想到的唯一例外是,如果您通常有混合的父容器
s,例如JPanel
s,它们有一个期望的组件和一个非期望的组件作为直接子级。在这种情况下,您必须检查每个组件