У меня есть 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
потребляющий всю свою область?
Что вы можете сделать, так это добавить фильтр в 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;
}