2010-09-29 103 views
8

我想創建一個應用程序,其中一些事件應該像處理父容器一樣處理。例如,我有一個包含JLabel的JPanel。頂級的JPanel現在實現了鼠標移動和拖拽。我需要做些什麼才能使事件看起來像是到達JPanel而不是標籤本身。 (改變源對象很重要)將事件傳遞給父節點

有沒有比實際實現事件並在父項中複製它們更好的解決方案? (這會在一些有5個孩子的物體後變得乏味)。

+0

爲什麼你需要做到這一點(例如)? – Pete 2010-09-29 03:58:53

+0

我有很多標籤的對象,無論第一次實際點擊哪個標籤,都應該可以拖動。現在,只有當我點擊元素的背景,而不是內部的任何標籤時,它們纔可以拖動。 – viraptor 2010-09-29 09:44:47

回答

10

在您的事件偵聽器中,您可以將事件分派給父組件。

作爲myEvent事件處理函數的參數:

Component source=(Component)myEvent.getSource(); 
source.getParent().dispatchEvent(myEvent); 

但是這種解決方案意味着創造的每個元素添加一個新的事件監聽。

所以,你可以創建一個單一的事件處理程序,並重新使用它,將它添加到所有選定的孩子,像這樣:

final Container parent=this; //we are a the parent container creation code 
MouseListener myCommonListener=new MouseListener() { 
    @Override 
    public void mouseClicked(MouseEvent e) { 
     parent.dispatchEvent(e); 
    } 
    @Override 
    public void mouseEntered(MouseEvent e) { 
     parent.dispatchEvent(e); 
    } 
    @Override 
    public void mouseExited(MouseEvent e) { 
     parent.dispatchEvent(e); 
    } 
    @Override 
    public void mousePressed(MouseEvent e) { 
     parent.dispatchEvent(e); 
    } 
    @Override 
    public void mouseReleased(MouseEvent e) { 
     parent.dispatchEvent(e); 
    } 
}; 

JLabel label=new JLabel("This is the first Label"); 
label.addMouseListener(myCommonListener); 

JLabel label2=new JLabel("This is the second Label"); 
label2.addMouseListener(myCommonListener); 
//... and so on 
+0

這在awt線程中創建了堆棧溢出(因爲父級將事件傳回給子控件)。有關如何解決此問題的任何想法?我無法編輯父類,但我需要它來獲取事件,但是無法對父代會返回到我的控件的事件進行操作。 – ed22 2015-02-24 10:16:09

+0

資源明智這是一個壞主意。沒有任何東西會增加很多開銷。刪除子元素上的鼠標偵聽器會更有效率。你可以看到我的答案如何遞歸地做到這一點。 – qwertzguy 2018-02-25 21:09:32

2

你應該把它分派到父事件之前轉換。轉換包括向父母親屬轉換座標。

public class RedispatchingMouseAdapter implements MouseListener, MouseWheelListener, MouseMotionListener{ 

    public void mouseClicked(MouseEvent e) { 
     redispatchToParent(e); 
    } 

    public void mousePressed(MouseEvent e) { 
     redispatchToParent(e); 
    } 

    public void mouseReleased(MouseEvent e) { 
     redispatchToParent(e); 
    } 

    public void mouseEntered(MouseEvent e) { 
     redispatchToParent(e); 
    } 

    public void mouseExited(MouseEvent e) { 
     redispatchToParent(e); 
    } 

    public void mouseWheelMoved(MouseWheelEvent e){ 
     redispatchToParent(e); 
    } 

    public void mouseDragged(MouseEvent e){ 
     redispatchToParent(e); 
    } 

    public void mouseMoved(MouseEvent e) { 
     redispatchToParent(e); 
    } 

    private void redispatchToParent(MouseEvent e){ 
     Component source = (Component) e.getSource(); 
     MouseEvent parentEvent = SwingUtilities.convertMouseEvent(source, e, source.getParent()); 
     source.getParent().dispatchEvent(parentEvent); 
    } 
} 
+0

您的回答實際上是對Tomas Narros的回答的評論。 – SeniorJD 2015-08-25 14:21:18

+0

@SeniorJD這是一個非常有效的答案。它只是建立在另一個答案上,可以獨立運作。如果Wojtek會更好地描述爲什麼需要這種調整,那會更好。 – 2015-08-25 18:17:19

+0

資源明智這是一個壞主意。沒有任何東西會增加很多開銷。刪除子元素上的鼠標偵聽器會更有效率。你可以看到我的答案如何遞歸地做到這一點。 – qwertzguy 2018-02-25 21:10:03

-1

鼠標事件被自動定位到有鼠標偵聽最深的部分。因此,要實現您的目標,您可以簡單地刪除JLabel上的所有鼠標偵聽器,並且它永遠不會被選爲鼠標事件的目標。

下面的代碼將在給定的組件和他們的孩子遞歸禁用鼠標監聽器:

private void disableMouseForComponent(Component... components) { 
    for (Component c : components) { 
     if (c instanceof Container) { 
      disableMouseForComponent(((Container) c).getComponents()); 
     } 
     for (MouseListener l : c.getMouseListeners()) { 
      c.removeMouseListener(l); 
     } 
     for (MouseMotionListener l : c.getMouseMotionListeners()) { 
      c.removeMouseMotionListener(l); 
     } 
    } 
} 
+0

-1'ed:你是否在意解釋原因? 這樣做是比添加派發給父級的偵聽器更好的資源。 – qwertzguy 2018-02-25 21:08:27