使用 FillLayout 在 Composite 上记录 SWT MouseEnter/Exit 事件
Record SWT MouseEnter/Exit events on a Composite with a FillLayout
我有一个 Composite
,我想在其中跟踪 SWT.MouseEnter
和 SWT.MouseExit
事件。然而,由于 FillLayout
.
,Composite
内部还有另一个 Composite
消耗了整个区域
一些示例代码来说明我在做什么:
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
永远不会记录鼠标 enter/exit 事件 除非 我稍微揭露一下它"area"。
我可以通过在其 FillLayout
上创建一些边距(注释掉第 21-22 行)来暴露一点 outerComp
,但这确实不理想。出于审美原因,我不能在 outerComp
上有很大的边距,并且如果我将鼠标快速移到复合材料上(我必须将我的将鼠标非常 慢慢移过 1px 边距以触发它)。
从我的项目的设计角度来看,我实际上不应该知道 outerComp
包含什么(或控件嵌套的深度),因此在其子项上设置事件侦听器也不理想.
如果 FillLayout
占据了它的所有区域,我是否仍然可以在 outerComp
上跟踪这些鼠标事件?
您可以做的是向 Display
添加过滤器,并在处理程序中检查 Event
的来源 Widget
是否是您的 Composite
.
这应该能让您了解如何操作:
public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell();
shell.setText("Whosebug");
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;
}
我有一个 Composite
,我想在其中跟踪 SWT.MouseEnter
和 SWT.MouseExit
事件。然而,由于 FillLayout
.
Composite
内部还有另一个 Composite
消耗了整个区域
一些示例代码来说明我在做什么:
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
永远不会记录鼠标 enter/exit 事件 除非 我稍微揭露一下它"area"。
我可以通过在其 FillLayout
上创建一些边距(注释掉第 21-22 行)来暴露一点 outerComp
,但这确实不理想。出于审美原因,我不能在 outerComp
上有很大的边距,并且如果我将鼠标快速移到复合材料上(我必须将我的将鼠标非常 慢慢移过 1px 边距以触发它)。
从我的项目的设计角度来看,我实际上不应该知道 outerComp
包含什么(或控件嵌套的深度),因此在其子项上设置事件侦听器也不理想.
如果 FillLayout
占据了它的所有区域,我是否仍然可以在 outerComp
上跟踪这些鼠标事件?
您可以做的是向 Display
添加过滤器,并在处理程序中检查 Event
的来源 Widget
是否是您的 Composite
.
这应该能让您了解如何操作:
public static void main(String[] args)
{
Display display = new Display();
Shell shell = new Shell();
shell.setText("Whosebug");
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;
}