【问题标题】:Record SWT MouseEnter/Exit events on a Composite with a FillLayout使用 FillLayout 在 Composite 上记录 SWT MouseEnter/Exit 事件
【发布时间】:2015-03-25 21:51:30
【问题描述】:

我有一个Composite,我想在其上跟踪SWT.MouseEnterSWT.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 永远不会记录鼠标进入/退出事件除非我暴露了一点它的“区域” .

我可以通过在 FillLayout 上创建一些边距来暴露一点 outerComp(注释掉第 21-22 行),但这确实不理想。出于美学原因,我在outerComp 上不能有很大的边距,如果我将鼠标快速移动到复合材料上,将边距大小减小到 1 并不能始终检测到鼠标事件(我必须移动鼠标 非常缓慢超过 1px 的边距以触发)。

从我项目的设计角度来看,我实际上不应该知道 outerComp 包含什么(或控件嵌套的深度),因此在其子级上设置事件侦听器也不理想。

如果FillLayout 占用了它的所有区域,我还能在outerComp 上跟踪这些鼠标事件吗?

【问题讨论】:

    标签: java swt mouseevent


    【解决方案1】:

    您可以做的是向Display 添加一个过滤器,并在处理程序中检查WidgetEvent 的来源是否是您的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;
    }
    

    【讨论】:

    • 我在某处读到过有关使用显示过滤器的信息,但不太明白。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 2017-06-28
    相关资源
    最近更新 更多