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

时间:2012-03-01 14:08:43

标签: java events focus swt hierarchy

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

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

2 个答案:

答案 0 :(得分:5)

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

DisplayŠ有无过滤器其中,像听众,被通知的事件,但是过滤器的区别在于它们的听众之前运行时,它们有机会取消事件,以及它们已通知整个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);
            }
        });
    }
}

请注意javadoc for Display关于使用过滤器的警告:

  

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

显然,你在任何一个解决方案在寻找性能的权衡 - 这取决于什么类型你提供应用程序和用户的工作流程,它可能更有意义添加焦点侦听器,当你调整,或者它可能使更有意义的是简单地听取所有焦点事件并忽略那些你不感兴趣的事件。

答案 1 :(得分:3)

您是否已查看此链接:SWT: notify a composite that it has a new child

根据上述链接中提出的解决方案,唯一可行的解​​决方案是使用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());
            }
        }
    }

}