Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to track mouse EXIT/ENTER/HOVER over composite?

The code below shows, that:

1) HOVER is totally ignored with composite. How to enable?

2) ENTER/EXIT are tracked, but when mouse entered child control region, parent composite receives EXIT event. How to make that entre area of a composite would serve as belonging to composite?

public class TryHover {

    public static void main(String[] args) {

        Display display = new Display();

        Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());

        Composite composite = new Composite(shell, SWT.BORDER);
        composite.setLayout(new GridLayout(1, false));

        Label label1 = new Label(composite, SWT.BORDER);
        label1.setText("Label 1");

        Label label2 = new Label(composite, SWT.BORDER);
        label2.setText("Label 2");

        composite.addListener(SWT.MouseEnter, new Listener() {

            @Override
            public void handleEvent(Event event) {
                System.out.println("ENTER");

            }
        });

        composite.addListener(SWT.MouseExit, new Listener() {

            @Override
            public void handleEvent(Event event) {
                System.out.println("EXIT");

            }
        });

        composite.addListener(SWT.MouseHover, new Listener() {

            @Override
            public void handleEvent(Event event) {
                System.out.println("HOVER");

            }
        });

        shell.pack();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }

    }
}

UPDATE

Yes, agree, if mouse is slow, it produces HOVER too.

Then the question is about ENTER/EXIT only: how to turn EXITs of on child controls?

like image 281
Suzan Cioc Avatar asked Oct 01 '22 13:10

Suzan Cioc


1 Answers

SWT.MouseHover is only triggered when the mouse is located over the Composite and doesn't move for a fraction of a second.

SWT.MouseMove is triggered on each movement of the mouse over the Composite.

So it really depends on what you want to achieve here.


As for the second part of your question: SWT does not propagate events up the widget hierarchy (with some exceptions).

You can however implement your own logic to determine when to listen to the events.

  • For SWT.MouseExit: Get the coordinates of the mouse and check if any of the children contains the mouse. If so, do nothing, if not, you left the Composite.
  • For SWT.MouseEnter: This is a bit more tricky. I came up with a solution that keeps track of the current Widget the mouse is moving over using a filter on the display. When you enter the Composite, you can check if the previous widget was a child. If so, do nothing.

private static Widget mouseControl = null;

public static void main(String[] args)
{
    Display display = new Display();

    /* Overall, keep track of the Widget the mouse is moving over */
    display.addFilter(SWT.MouseMove, new Listener()
    {
        @Override
        public void handleEvent(Event e)
        {
            mouseControl = e.widget;
        }
    });

    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());

    final Composite composite = new Composite(shell, SWT.BORDER);
    composite.setLayout(new GridLayout(1, false));

    Label label1 = new Label(composite, SWT.BORDER);
    label1.setText("Label 1");

    Label label2 = new Label(composite, SWT.BORDER);
    label2.setText("Label 2");

    composite.addListener(SWT.MouseEnter, new Listener()
    {
        @Override
        public void handleEvent(Event event)
        {
            /* Check if the mouse was previously moving over a child (you could
             * even do recursive search here) */
            for (Control child : composite.getChildren())
            {
                if (child.equals(mouseControl))
                    return;
            }
            System.out.println("ENTER");
        }
    });

    composite.addListener(SWT.MouseExit, new Listener()
    {
        @Override
        public void handleEvent(Event event)
        {
            /* Check if the mouse is now located over a child (you could
             * even do recursive search here) */
            for (Control child : composite.getChildren())
            {
                if (child.getBounds().contains(new Point(event.x, event.y)))
                    return;
            }
            System.out.println("EXIT");
        }
    });

    composite.addListener(SWT.MouseHover, new Listener()
    {

        @Override
        public void handleEvent(Event event)
        {
            System.out.println("HOVER");
        }
    });

    shell.pack();
    shell.open();
    while (!shell.isDisposed())
    {
        if (!display.readAndDispatch())
            display.sleep();
    }
}
like image 64
Baz Avatar answered Oct 05 '22 11:10

Baz