글쓴이: Scott Violet (Swing 아키텍트)
ActionListener
오브젝트는 통상적으로 사용자 인터페이스 동작에 의해 트리거되는 애플리케이션 특유의 기능을 캡슐화한다(이것은 항상 적용되는 것은 아니며, javax.swing.Timer
역시 ActionListener
를 사용한다). 일례로, 브라우저의 "뒤로" 버튼을 클릭하면 이전 페이지로 되돌아가는 작업을 담당하는 ActionListener
의 구현이 통지되는데, 이는 다음과 같은 형태를 띨 것이다.
private class GoBackActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
browserComponent.show(getLastURL());
}
}
backButton.addActionListener(new GoBackActionListener());
backButton.setIcon(...);
backButton.setEnabled(false);
사용자가 임의의 Swing/AWT 애플리케이션을 작성했다면 코드의 형태는 아마도 이와 유사할 것이다. 단순하지만 잘 작동하는 것을 알 수 있다.
페이지를 되돌릴 수 있는지 여부에 따라 버튼을 계속 이네이블(enable)하려고 하면 어떤 상황이 발생하게 되는지 생각해보자. 이런 경우, 사용자가 setEnabled
메소드를 호출하려면 backButton
오브젝트에 대한 핸들이 필요하다. 사용자가 동일한 기능을 가진 메뉴 항목을 사용할 경우에는 해당 메뉴 항목 또는 GoBackActionListener
기능을 사용해야 하는 다른 사용자 인터페이스 컴포넌트에 대한 핸들을 유지할 필요가 있다. 이것은 다소 번거로운 작업일 뿐 아니라, 특히 이 경우 모든 종류의 레퍼런스가 사용자 애플리케이션의 호스팅 컴포넌트로 반환되는 결과를 낳게 하기도 한다.
다음 코드는 메뉴 항목을 구성하여 GoBackActionListener
에 와이어하는 과정을 보여준다.
backMenuItem.addActionListener(new GoBackActionListener());
backMenuItem.addActionListener(new GoBackActionListener());
backMenuItem.setText(...);
backMenuItem.setMnemonic(...);
backMenuItem.setDisplayedMnemonicIndex(...);
backMenuItem.setAccelerator(...);
backMenuItem.setEnabled(false);
Action
인터페이스의 목적은 바로 이런 문제를 해결하는 데 있다. Action
은 ActionListener
의 기능 부분을 캡슐화할 뿐 아니라 사용자 인터페이스 컴포넌트에 적합한 기능에 대한 기술(description)까지 포함하고 있으며, 이 기술에는 사용자 인터페이스 컴포넌트의 이네이블 여부에 관한 정보가 포함된다. Action
의 이네이블 상태가 변경되면 Action
을 청취하는 사용자 인터페이스 컴포넌트가 적절하게 업데이트된다. 이전의 예제를 Action
으로 대체할 경우, 사용자가 Action
의 이네이블 상태를 변경하면 그 결과로 버튼 및 메뉴 항목이 업데이트된다. 이에 관한 코드는 대략 다음과 같다.
private class GoBackAction extends AbstractAction {
public GoBackAction() {
putValue(Action.NAME, "...");
putValue(Action.LARGE_ICON_KEY, ...);
putValue(Action.SMALL_ICON, ...);
putValue(Action.MNEMONIC_KEY, ...);
putValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY, ...);
putValue(Action.ACCELERATOR_KEY, ...);
putValue(Action.SHORT_DESCRIPTION, ...);
setEnabled(false);
}
public void actionPerformed(ActionEvent e) {
browserComponent.show(getLastURL());
}
}
Action goAction = new GoBackAction();
backButton.setHideActionText(true);
backButton.setAction(goAction);
backMenuItem.setAction(goAction);
이 예제와 앞의 예제에 여러 차이가 있음을 알 수 있다. 특히, 텍스트, 아이콘 및 사용자 인터페이스 컴포넌트의 기타 속성을 구성하는 대신 GoBackAction
에 이 모든 정보가 포함되고, 사용자 인터페이스 컴포넌트에 GoBackAction
을 첨부하면 사용자 인터페이스 컴포넌트는 Action
에서 그 상태를 구성한다. 예를 들어, JButton 컴포넌트는 Action
오브젝트에서 아이콘, 텍스트, 연상기호(mnemonic), mnemonic index, 툴팁 텍스트, 액션 명령어 키 및 이네이블 상태를 획득하게 되는데, 이는 go back
이벤트 기술(description)이 단일 장소에서 캡슐화되고 모든 호스팅 컴포넌트에 복제될 필요가 없다는 점에서 상당히 유용하다.
Java SE 6의 최신 개선사항을 아직 접하지 못한 사람이라면 새로운 키와 메소드가 포함되었다는 점에 주목하게 될 것이다. 특히 DISPLAYED_MNEMONIC_INDEX_KEY
, LARGE_ICON_KEY
값과 setHideActionText
메소드 모두 Java SE 6에서 새로 소개되었으며, 본 예제에서는 볼 수 없지만 SELECTED_KEY
도 새로 포함되었다. 또한 Java SE 6에는 각 컴포넌트가 지원하는 속성에 관한 집중 기술(centralized descriptions)이 포함되어 있다. 모든 구체적인 사항은 Action
의 클래스 레벨 문서를 참조할 것.
ActionListener
사용 시, 다음의 이벤트를 생성하는 각각의 사용자 인터페이스 컴포넌트의 이네이블 상태를 명확하게 업데이트해야 한다.
backButton.setEnabled(...);
backMenuItem.setEnabled(...);
Action
클래스를 사용할 경우 코드는 다음과 같다.
goBackAction.setEnabled(...);
Action
에 첨부된 모든 사용자 인터페이스 컴포넌트는 Action
이 변경될 때마다 적절히 업데이트된다. 이제 사용자는 여러 컴포넌트 전체가 아닌 Action
만을 레퍼런스하면 된다.
직접 Action
을 변경하고 그 상태가 사용자 인터페이스 컴포넌트에 적절히 반영되도록 하는 기능은 갖가지 상황에서 매우 편리하게 이용할 수 있다. 예를 들어, undo/redo 메뉴 항목의 경우 종종 텍스트에 undo/redo가 수행할 동작이 반영되는데, 가령 "Undo Paste"나 "Undo Edit" 텍스트는 undo/redo 메뉴 항목을 레이블링할 수 있다. 또한 사용자가 Action
의 NAME
속성을 변경하면 메뉴 항목과 Action
을 사용하는 기타의 모든 컴포넌트들도 적절하게 변경된다.
Action
클래스에 관한 자세한 내용을 보려면 다음 링크를 참조하기 바란다.