Запишите события SWT MouseEnter / Exit на Composite с помощью FillLayout

1

У меня есть Composite на котором я хочу отслеживать SWT.MouseEnter и SWT.MouseExit. Однако у Composite есть другой Composite внутри, который поглощает всю область, из-за FillLayout.

Пример кода для иллюстрации того, что я делаю:

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;

public class EventListenerTest {

    public static void main(String[] args) {

        Display display = new Display();
        Shell shell = new Shell(display);

        // Set up the outer Composite
        Composite outerComp = new Composite(shell, SWT.BORDER);
        FillLayout fl = new FillLayout();
        // fl.marginHeight = 15;
        // fl.marginWidth = 15;
        outerComp.setLayout(fl);

        // Set up a nested Composite
        Composite innerComp = new Composite(outerComp, SWT.BORDER);

        // Set a listener on the outer Composite for a MouseEnter event
        outerComp.addListener(SWT.MouseEnter, new Listener() {
            @Override
            public void handleEvent(Event e) {
                System.out.println("Mouse ENTER event");
            }

        });

        // Similarly, for a MouseExit event
        outerComp.addListener(SWT.MouseExit, new Listener() {
            @Override
            public void handleEvent(Event e) {
                Composite comp = (Composite) e.widget;
                // Don't report if positioned over a child control
                for (Control child : comp.getChildren()) {
                    if (!child.getBounds().contains(new Point(e.x, e.y)))
                        System.out.println("Mouse EXIT event");
                }
            }

        });

        outerComp.pack();
        outerComp.layout();

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

        display.dispose();
        return;
      }
}

К сожалению, из-за того, что innerComp заполняет всю полноту своего родителя, outerComp никогда не записывает события ввода /outerComp мыши, если я не выставил немного его "области".

Я могу выставить немного outerComp, создав некоторые поля на FillLayout (прокомментированные строки 21-22), но это действительно не идеально. По эстетическим соображениям я не могу иметь огромные поля на outerComp, и уменьшение размера поля до 1 не будет последовательно обнаруживать события мыши, если я быстро передвигаю мышь над композитом (мне нужно очень медленно перемещать мышь 1px margin для запуска).

С точки зрения дизайна моего проекта я не должен знать, что содержит outerComp (или насколько глубокое гнездо для элементов управления), поэтому установка прослушивателей событий на его детей также не идеальна.

Есть ли способ отслеживать эти события мыши на outerComp если у него есть FillLayout потребляющий всю свою область?

Теги:
mouseevent
swt

1 ответ

3
Лучший ответ

Что вы можете сделать, так это добавить фильтр в Display и в обработчик, проверьте, является ли Widget, являющийся источником Event дочерним элементом вашего Composite.

Это должно дать вам представление о том, как это сделать:

public static void main(String[] args)
{
    Display display = new Display();
    Shell shell = new Shell();
    shell.setText("StackOverflow");
    shell.setLayout(new GridLayout(2, true));

    final Composite left = new Composite(shell, SWT.NONE);
    Composite right = new Composite(shell, SWT.NONE);
    left.setLayout(new GridLayout(3, true));
    right.setLayout(new GridLayout(3, true));

    for (int i = 0; i < 6; i++)
    {
        new Label(left, SWT.NONE).setText("label-" + i);
        new Label(right, SWT.NONE).setText("label-" + i);
    }

    display.addFilter(SWT.MouseMove, new Listener()
    {
        @Override
        public void handleEvent(Event e)
        {
            if (isChildOrSelf(e.widget, left))
                System.out.println(e);
        }
    });

    shell.pack();
    shell.open();

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

    display.dispose();
}

private static boolean isChildOrSelf(Widget child, Composite parent)
{
    if(child == parent)
        return true;

    for (Control c : parent.getChildren())
    {
        if (c instanceof Composite)
        {
            boolean result = isChildOrSelf(child, (Composite)c);
            if (result)
                return true;
        }
        else if (c == child)
            return true;
    }

    return false;
}
  • 0
    Я где-то читал об использовании фильтра дисплея, но не мог понять это. Спасибо!
  • 0
    @AnnaW. Нет проблем, рад, что это сработало для вас.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню