如何通知复合材料的孩子收到/失去焦点?

我有一个SWT Composite ,我需要传递给其他代码,这些代码会随意添加子代码。 有没有办法通知复合材料的孩子收到并失去了焦点?

为了确保清楚,我无法为每个孩子添加听众,因为我不负责创建这些控件。 可以随时添加一个孩子。

如Favonius所述,您可以挂钩布局事件(如SWT.Resize以确定何时进行绘制并重新计算子层次结构,并根据需要添加侦听器。 另一种选择只是听取所有焦点事件,只关注那些你感兴趣的控件。

Display具有与侦听一样被通知事件的filter,但是filter的不同之处在于它们在侦听器之前运行,它们有机会取消事件,并且它们被通知整个Display上的所有类型的事件。

因此,您可以使用Filter检查所有焦点事件,并确定它是否是您感兴趣的事件。例如:

 public class MyControl extends Composite { private final Listener focusListener; public MyControl(final Composite parent, final int style) { /* initialize the control... */ focusListener = new Listener() { public void handleEvent(Event event) { if (!(event.widget instanceof Control)) { return; } boolean isOurChild = false; for (Control c = (Control) event.widget; c != null; c = c.getParent()) { if (c == container) { isOurChild = true; break; } } if (isOurChild) { System.out.println("Our child is " + (event.type == SWT.FocusIn ? "focused" : "unfocused")); } } }; getDisplay().addFilter(SWT.FocusIn, focusListener); getDisplay().addFilter(SWT.FocusOut, focusListener); addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { getDisplay().removeFilter(SWT.FocusIn, focusListener); getDisplay().removeFilter(SWT.FocusOut, focusListener); } }); } } 

请注意Display有关使用filter的警告的javadoc :

出于性能,调试和代码维护的原因,通常应避免使用它们。

显然,您正在考虑任一解决方案中的性能权衡 – 取决于您提供的应用程序类型和用户的工作流程,在resize时添加焦点侦听器可能更有意义,或者可能更有意义只需听取所有焦点事件,忽略那些你不感兴趣的事件。

您是否检查过此链接: SWT:通知复合材料它有一个新的孩子

根据上述链接中提出的解决方案,唯一可能的解决方案是使用resize事件。 基于此,请参阅以下代码,该代码在所有直接子节点上添加焦点侦听器。 虽然解决方案本身并不是很优雅。

测试代码

 import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; public class SWTApplication { public static void main(String[] args) { new SWTApplication().initSystem("Children Notification"); } private Display display; private Shell shell; public void initSystem(String windowName) { display = new Display(); shell = new Shell(display); shell.setText(windowName); shell.setLayout(new GridLayout(6, true)); shell.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); final TestFocusListener listener = new TestFocusListener(); shell.addControlListener(new ControlListener() { public void controlResized(ControlEvent e) { if(e.getSource() instanceof Shell) { Shell s = (Shell)e.getSource(); Control[] children = s.getChildren(); for (int i = 0; i < children.length; i++) { Control c = children[i]; c.removeFocusListener(listener); c.addFocusListener(listener); } } } public void controlMoved(ControlEvent e) { } }); createControls(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } private void createControls() { String[] name = {"a", "b", "c", "d", "e", "f"}; for(int i=0; i<6; i++) { Button button = new Button(shell, SWT.PUSH); button.setText(name[i] + " button"); button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); shell.setSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); } } class TestFocusListener implements FocusListener { public void focusGained(FocusEvent e) { Object src = e.getSource(); if(src instanceof Button) { System.out.println("Focus gained: " + ((Button)src).getText()); } } public void focusLost(FocusEvent e) { Object src = e.getSource(); if(src instanceof Button) { System.out.println("Focus lost: " + ((Button)src).getText()); } } } }