2009-06-27 66 views
2

我正在尋找一種簡單的方法來製作一個Swing組件將所有收到的 事件轉發給其父容器(或者甚至所有家長,直至根)。Swing:如何實現從子組件到父容器的所有事件轉發?

編輯
我在哪裏需要這個?我有一個圖編輯器。組件必須轉發按鍵和 鼠標點擊(只要用戶單擊該組件的子元素 ,就自行設置爲「活動」)。

首先,讓我介紹一下我現有的解決方案。這是一個解決方法。

public interface IUiAction { 
void perform(Component c); 
} 

public static void performRecursiveUiAction(Container parent, IUiAction action) { 
if (parent == null) { 
    return; 
} 

for (Component c : parent.getComponents()) { 
    if (c != null) { 
    action.perform(c); 
    } 
} 

for (Component c : parent.getComponents()) { 
    if (c instanceof Container) { 
    performRecursiveUiAction((Container) c, action); 
    } 
} 
} 

/** 
* 1) Add listener to container and all existing components (recursively). 
* 2) By adding a ContainerListener to container, ensure that all further added 
* components will also get the desired listener. 
* 
* Useful example: Ensure that every component in the whole component 
* tree will react on mouse click. 
*/ 
public static void addPermanentListenerRecursively(Container container, 
    final IUiAction adder) { 

final ContainerListener addingListener = new ContainerAdapter() { 
    @Override 
    public void componentAdded(ContainerEvent e) { 
    adder.perform(e.getChild()); 
    } 
}; 

// step 1) 
performRecursiveUiAction(container, adder); 

// step 2) 
performRecursiveUiAction(container, new IUiAction() { 
    @Override 
    public void perform(Component c) { 
    if (c instanceof Container) { 
    ((Container) c).addContainerListener(addingListener); 
    } 
    } 
}); 
} 

用法:

addPermanentListenerRecursively(someContainer, 
    new IUiAction(
    @Override 
    public void perform(Component c){ 
     c.addMouseListener(somePermanentMouseListener); 
    } 
) 
); 

通過查看代碼,你會說這是一個很好的概念?
我目前的概念的問題是:它只轉發事件,爲其手動指定偵聽器。

你能推薦一個更好的嗎?

+0

我在某些swing事件上遇到了consume()方法,這個方法用於指示您在處理程序中使用了該事件。我認爲相反的是你需要的。 – akarnokd 2009-06-27 14:27:04

+0

例如:鼠標點擊,鼠標拖動(「激活」視覺圖元素),各種熱鍵,... – 2009-06-27 14:30:20

回答

2

如果視圖中的每個組件都處理相同的鼠標事件,它看起來會有點棘手。即如果用戶拖動項目1,項目2也會處理這些事件?如果我理解正確,您正在尋求thisthis.parentthis.parent.parent處理this上的鼠標操作。在這種情況下,遞歸會上升,而不是下降。

您可以創建一個Interface這樣的:

public interface MyInterface() { 
    public void performSpecialAction(Event event); 
} 

你再有你的容器實現這個接口。那麼你的組件將需要此調用納入到相應事件處理:

public static void performRecursiveUiAction(Component comp, Event event) { 
    if (comp.getParent() == null) { 
    return; 
    } 
    if (comp.getParent() instanceof MyInteface) { 
    ((MyInterface)comp.getParent()).performSpecialAction(event); 
    } 
    ThisUtility.performRecursiveUiAction(comp.getParent(), event); 

}

3

根據您的情況我對事物的鍵盤側的建議:

你可以使用擺動的擊鍵設施爲:

JRootPane rp = getRootPane(); 

KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0, false); 
rp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, "F2"); 
rp.getActionMap().put("F2", new AbstractAction() { 
public void actionPerformed(ActionEvent e) { onF2Action(); } }); 

這樣,您就可以註冊「全球」事件處理器的快捷方式。

雖然它可能在你的情況有一些限制。

對於鼠標事件,我會創建一個遞歸函數,它將MouseAdapter實例添加到每個目標組件。例如:

void addToAll(Container c, MouseAdapter a) { 
    for (Component p : c.getComponents()) { 
     if (p instanceof InterrestingComponent) { 
      p.addMouseListener(a); 
      p.addMouseMotionListener(a); 
      p.addMouseWheelListener(a); 
     } else 
     if (p instanceof Container) { 
      addToAll((Container)p, a); 
     } 
    } 
} 

只是爲了捕捉這個概念。您可能需要不同的或多個接收器用於各種組件。

編輯:對不起,我不小心說了WindowAdapter而不是MouseAdapter。

+0

在旁註:關於Swing與Delphi相反的好事之一,它可以讓你輕鬆在任何地方都可以注入多個事件處理程序,而Delphi的GUI模型基於單一的onSomething方法。 – akarnokd 2009-06-27 15:25:27

1
  • 無論你從組件的事件,在這種情況下,你註冊,你需要的聽衆捕獲事件。 Pro是您可以選擇捕捉事件的地方,並且您可以選擇按來源選擇接收它們。 Con是你必須儘可能註冊儘可能多的聽衆...
  • 或者使用玻璃面板,並在它傳播到組件前捕獲所有信息。在這種情況下,您將它們全部捕獲,並且如果要將它們綁定到玻璃窗格下的組件,則必須編寫自定義處理代碼。 (假設您將玻璃窗格保留爲空)以下是一個在事件到達組件之前捕獲事件的示例,甚至可以將事件轉發給所選組件:http://download.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane
  • 中間層是使用分層窗格創建透明組件任何你需要的東西)。

你也可以消耗()事件......你的主要問題是你要麼在捕捉事件之前捕捉事件(從頭開始編寫自定義處理)它們之間或之後(並且從處理中產生一些干擾你可能需要破解),但是你不能通過繼承任何東西來修改處理代碼本身(或者你可以嗎?從未見過......)。

相關問題