How to be notified that a composite's child received/lost focus?

跟風遠走 提交于 2019-12-20 02:34:10

问题


I have an SWT Composite that I need to pass to some other code which will add children to it at will. Is there any way to be notified that a child of the composite received and lost focus?

Just to make sure it's clear, I cannot add listeners to each child, because I'm not in charge of creating those controls. A child could be added at any time.


回答1:


As noted by Favonius, you can hook layout events like SWT.Resize to determine when you're being painted and recompute your child hierarchy, adding listeners as appropriate. Another option is simply to listen for all focus events and only pay attention to those that are for controls that you're interested in.

Displays have filters which, like listeners, are notified of events, however filters differ in that they are run before listeners, they have the opportunity to cancel events, and they are notified for all of a type of event on the entire Display.

You could thus use a Filter to examine all focus events and determine if it's one that you're interested in. For example:

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);
            }
        });
    }
}

Do note the javadoc for Display's warnings about using filters:

They should generally be avoided for performance, debugging and code maintenance reasons.

Obviously you're looking at performance trade-offs in either solution - depending on what type of application you're delivering and your users' workflow, it may make more sense to add focus listeners when you resize, or it may make more sense to simply listen to all focus events and ignore the ones you're not interested in.




回答2:


Have you checked this link: SWT: notify a composite that it has a new child

As per the proposed solution in the above link the only possible solution is to use the resize event. Based on that see the following code, which adds a focus listener on all the immediate child nodes. Though the solution itself is not very elegant.

Test Code

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());
            }
        }
    }

}


来源:https://stackoverflow.com/questions/9517634/how-to-be-notified-that-a-composites-child-received-lost-focus

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!