给定Swing容器和坐标,如何找到制造鼠标事件的来源?

时间:2015-10-27 18:55:47

标签: java swing

我有一个容器,例如JFrame或JComponent。容器可能包含可能具有鼠标侦听器的组件,例如按钮,面板等。我想要做的是创建一个MouseEvent并将其添加到系统事件队列中,即模拟当用户点击某个位置的容器时会发生什么。我知道点击相对于容器的坐标,但我不知道如何安排容器的子孙等。

到目前为止我所拥有的是以下内容

    Component source = ????? ;
    final MouseEvent ev = new MouseEvent(source, id, now, modifiers, x, y,
                        xAbs, yAbs, clickCount, popupTrigger, button) ;
    SwingUtilities.invokeAndWait(new Runnable() {
        @Override public void run() {
            EventQueue q = Toolkit.getDefaultToolkit().getSystemEventQueue() ;
            q.postEvent(ev);
        } });

如果我能找到正确的子组件source,这是有效的。但是我该怎么做呢?

java.awt.Container中有一个名为getMouseEventTarget的方法,不幸的是,这不是公开的。

我知道我可以使用java.awt.Robot执行与此类似的操作,但我不想实际移动鼠标指针。我希望能够在无头模式下执行此操作,我认为Robot可能无法正常工作。

修改

这是我尝试解决方案。它基于非公共方法java.awt.Container.getMouseEventTarget。我想找到一个更简单,更正确的解决方案。

static Triple<Component,Integer,Integer> searchForMouseEventSource( Component p, int x, int y ) {
    synchronized( p.getTreeLock() ) {
        return searchForMouseEventSourceImpl( p, x, y ) ;
    }
}
static private Triple<Component,Integer,Integer> searchForMouseEventSourceImpl( Component comp, int x, int y ) {
    // Based on getMouseEventTarget in java.awt.container
    // Search for a descendant component that can take the event.
    if( comp instanceof Container ) {
        Container cont = (Container) comp ;
        for (int i = 0; i < cont.getComponentCount(); i++) {
            Component child = cont.getComponent(i) ;
            if( child != null && child.isVisible() ) {
                int childX = child.getX() ;
                int childY = child.getY();
                if( child.contains(x - childX, y - childY) ) {
                    Triple<Component,Integer,Integer> result
                        = searchForMouseEventSourceImpl( child, x-childX, y-childY );
                    if( result != null ) return result ;
                }
            }
        }
    }
    // If we get here there, is no descendant that can take the event.
    if( comp.contains(x,y) && takesMouseEvents( comp ) ) {
        return new Triple<Component,Integer,Integer>( comp, x, y) ; }
    else {
        return null ; }
}

static boolean takesMouseEvents( Component comp ) {
    // The following is what we want (from java.awt.Container)
    //return (comp.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0
    //        || (comp.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0
    //        || (comp.eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0
    //        || comp.mouseListener != null
    //        || comp.mouseMotionListener != null
    //        || comp.mouseWheelListener != null;
    // The next line covers the last 3 cases, I think.
    return comp.getMouseListeners().length != 0 
        || comp.getMouseMotionListeners().length != 0
        || comp.getMouseWheelListeners().length != 0 ;
}

static class Triple<T,U,V> {
    public T first ; 
    public U second ;
    public V third ;
    public Triple( T first, U second, V third ) {
        this.first = first ; this.second = second ; this.third = third ; }
}

1 个答案:

答案 0 :(得分:1)

  

如果我能找到合适的子组件作为源,这是有效的。但是我该怎么做呢?

Component child = container.getComponentAt( Point );

编辑:

这可能会做你想要的:

Component child = SwingUtilities.getDeepestComponentAt(parent, x, y) 
相关问题