2012-08-06 75 views
9

我需要幫助來了解Swing中的事件傳播。我知道每個事件只能由一個組件處理。因此,當我有一個面板outside與一些兒童面板inside,我添加mouseListeners他們兩個,將調用inside之一。這很好,這是預期的行爲。子組件中的MouseMotionListener禁用父組件中的MouseListener

但我不明白,在下列情況下的行爲: inside註冊了一個MouseMotionListener和outside註冊一個MouseListener的。我期望inside消耗所有MouseMotionEvents和outside來接收MouseEvents,因爲inside上沒有正常MouseEvents的偵聽器。但事實並非如此,inside以某種方式消耗所有MouseEvent不僅僅是MouseMotionEvents。

下面的代碼說明了這個問題:

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class EventTest { 
public static void main(String... args) { 
    SwingUtilities.invokeLater(new Runnable(){ 
     @Override 
     public void run() { 
      JComponent inside = new JPanel(); 
      inside.setBackground(Color.red); 
      inside.setPreferredSize(new Dimension(200,200)); 
      MouseMotionListener mm = new MouseMotionListener() { 
       @Override 
       public void mouseDragged(MouseEvent arg0) { 
        System.err.println("dragged");      
       } 
       @Override 
       public void mouseMoved(MouseEvent arg0) { 
        System.err.println("moved"); 
       } 
      }; 
      // next line disables handling of mouse clicked events in outside 
      inside.addMouseMotionListener(mm); 

      JComponent outside = new JPanel(); 
      outside.add(inside); 
      outside.setPreferredSize(new Dimension(300,300)); 
      outside.addMouseListener(new MouseAdapter() { 
       public void mouseClicked(MouseEvent e) { 
        System.err.println("clicked"); 
       } 
      }); 

      JFrame frame = new JFrame(); 
      frame.add(outside); 
      frame.pack(); 
      frame.setVisible(true); 
     } 
    }); 
    } 
} 

我可以解決此問題通過註冊監聽器上inside所有事件的父組件可能會感興趣的,然後調用dispatchEvent到事件轉發到家長。

a)有人可以指點我一些文檔,其中描述了這種行爲? MouseEvent的javadoc讓我覺得我的期望是正確的。所以,我需要一個不同的描述來理解它。

b)是否有更好的解決方案比以上草圖?

感謝, 席

編輯:現在還不清楚,爲什麼搖擺的行爲這種方式。但是看起來,獲得這些東西的唯一方法就是手動轉發事件,我會這樣做。

+0

+1 [SSCCE(http://sscce.org/)。 – trashgod 2012-08-06 17:59:22

回答

8

a)通過design,只有當鼠標組件上沒有鼠標偵聽器時,Java鼠標事件纔會「冒泡」。

b)您可以將轉發事件到另一個組件,如here及以下所示。

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class EventTest { 

    public static void main(String... args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       final JComponent outside = new JPanel(); 
       JComponent inside = new JPanel(); 
       inside.setBackground(Color.red); 
       inside.setPreferredSize(new Dimension(200, 200)); 
       inside.addMouseMotionListener(new MouseAdapter() { 

        @Override 
        public void mouseDragged(MouseEvent e) { 
         System.err.println("dragged"); 
        } 

        @Override 
        public void mouseMoved(MouseEvent e) { 
         System.err.println("moved inside"); 
         outside.dispatchEvent(e); 
        } 
       }); 

       outside.add(inside); 
       outside.setPreferredSize(new Dimension(300, 300)); 
       outside.addMouseMotionListener(new MouseAdapter() { 

        @Override 
        public void mouseMoved(MouseEvent arg0) { 
         System.err.println("moved outside"); 
        } 
       }); 

       JFrame frame = new JFrame(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(outside); 
       frame.pack(); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 
1

非常相似,trashgod的答案 - 您可以使用一個MouseAdapter爲您的移動偵聽器,並重寫它轉發要由家長來處理任何事件。這應該只添加一小部分代碼。

 MouseAdapter mm = new MouseAdapter() { 
      @Override 
      public void mouseDragged(MouseEvent arg0) { 
       System.err.println("dragged");      
      } 
      @Override 
      public void mouseMoved(MouseEvent arg0) { 
       System.err.println("moved"); 
      } 
      @Override 
      public void mouseClicked(MouseEvent e) { 
       outside.dispatchEvent(e); 
      } 
     }; 
     // For forwarding events 
     inside.addMouseListener(mm); 
     // For consuming events you care about 
     inside.addMouseMotionListener(mm); 

我也找不到任何方法使用dispatchEvent(e)方法。我認爲你被這條路線困住了。

0

此制定了我:

Ellipse2D mCircle = new Ellipse2D.Double(x,y,size,size); 

    void PassMouseEvent(MouseEvent e) { 
    getParent().dispatchEvent(e); 
    } 

    public void mousePressed(MouseEvent arg0) { 
    if(mCircle.contains(arg0.getX(), arg0.getY())) { 
     // Do stuff if we click on this object 
    } else { 
     // Pass to the underlying object to deal with the mouse event 
     PassMouseEvent(arg0); 
    } 
    } 
相關問題