메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

자바 스윙: 메뉴와 툴바 - 제 3편

한빛미디어

|

2003-04-17

|

by HANBIT

13,183

저자: Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole, 역 한빛리포터 이상화

본 기사는『Java Swing, 2nd Edition』의 메뉴와 툴바에 대한 내용을 다룬 챕터를 요약한 기사 중 3번째 기사에 해당하는 글이다. 이번 시간에는 JMenuItem 클래스를 배워보자.


이전기사 보기


자바 스윙: 메뉴와 툴바 - 제 1편 『Java Swing, 2nd Edition』에서 메뉴와 툴바에 대한 내용을 다룬 챕터를 요약한 기사로 스윙 메뉴에 대한 설명을 하고 있다.

자바 스윙: 메뉴와 툴바 - 제 2편 『Java Swing, 2nd Edition』에서 메뉴와 툴바에 대한 내용을 다룬 챕터를 요약한 기사로 JmenuBar 클래스를 가지고 메뉴 바 선택 모델에 대한 설명을 하고 있다.


JMenuItem 클래스

메뉴에 관해 논의하기 앞서 JMenuItem 클래스를 살펴보자. [그림 14-6]은 JMenuItem 컴포넌트의 클래스 다이어그램을 보여주고 있다


[그림 14-6] JMenuItem 클래스 다이어그램

JmenuItem는 메뉴의 일부분으로 사용되는 문자열과 이미지를 위한 래퍼(wrapper) 클래스 역할을 한다. JMenuItem 클래스는 원래 상세화된 버튼으로 AbstractButton 클래스를 상속하고 있다. 이런 특징들은 일반적인 버튼과는 다소 차이가 있는데 마우스 포인터가 메뉴 아이템 위로 드래그 될 때 스윙은 메뉴 아이템이 "선택되었다" 라고 판단한다. 사용자가 마우스 버튼을 메뉴 아이템 위에서 눌렸다가 놓을 경우에 해당되는 동작을 취하게 되는 것이다.

여기서 "선택되었다"라는 용어는 상당히 까다로운 단어다. 스윙은 마우스가 메뉴 아이템 위로 올려졌을 때 MenuSelectionManagerMenuElement 인터페이스를 상속한 클래스 때문에 선택되었다고 생각하는 반면 2개의 지속적인 상태를 유지하는 체크박스 버튼과 같은 것은 클릭이 되어야 선택된 것이라 여겨진다. 그래서 메뉴 아이템이 선택되면 버튼 모델은 진하게 강화되고 반대로 메뉴 아이템이 선택 해제되면 진하게 강화되었던 것이 원래대로 돌아온다. 마지막으로 메뉴 아이템 위에 마우스 버튼이 놓이게 되면 AbstractButtondoClick() 메소드가 호출된다.

메뉴 아이템 단축키

메뉴 아이템은 키보드 단축키와 밑줄 단축키를 가질 수 있다. 밑줄 단축키란 단일 문자열의 밑줄을 통해 단축키를 표현하는 것이다. 반면에 키보드 단축키는 JComponent을 상속하고 외형과 위치가 Look & Feel(역주 : 이후 L&F)을 따른다는 유일한 단점을 가지고 있다. [그림 14-7]은 밑줄 단축키와 키보드 단축키를 보여주고 있다.


[그림 14-7] 밑줄 단축키와 키보드 단축키

키보드 단축키와 밑줄 단축키 둘 다 마우스 클릭과 같은 불필요한 행동을 생략할 수 있게 해준다. 그러나 밑줄 단축키는 메뉴가 화면에 나타날 때만 작동한다. 이에 반해 키보드 단축키는 메뉴가 보이건 보이지 않건 애플리케이션이 활성화 되어 있는 동안 항상 작동한다. 또한 키보드 단축키는 모든 플랫폼에서 동작하지만 밑줄 단축키는 그렇지 못하다.

우리는 프로그래밍 관점에서 두 가지 단축키를 살펴볼 것이다. 키보드 단축키를 이용하면 기능키, 명령키, Shift/Ctrl/Alt와 같은 조합을 통해 이루어 지는 키처럼 다양한 사용법을 취할 수 있다. 모든 조합은 플랫폼과 L&F에 사용되는 몇몇 키를 제외하고 대부분 javax.swing.KeyStroke 클래스로 나타낼 수 있다. 그러므로 다음과 코드와 같이 기본 툴킷의 menuShortcutKeyMask 속성과 KeyStroke 객체의 accelerator 속성을 이용하여 키보드 단축키에 메뉴 아이템을 할당할 수 있다.
JMenuItem m = new JMenuItem("Copy");
m.setAccelerator(KeyStroke.getKeyStroke("C",
    Toolkit.getDefaultToolkit(  ).getMenuShortcutKeyMask(  ), false));
이것은 메뉴 아이템을 Ctrl-C에 할당하고 L&F에 따라 메뉴 아이템의 오른쪽 위치에 나타나게 한다. KeyStroke 클래스는 『Java Swing, 2nd Editon』 Chapter 27에 자세하게 나와있다.

다음으로 그리 널리 사용되진 않지만 AbstractButton 클래스의 mnemonic 속성을 이용하여 밑줄 단축키를 설정하는 방법이다.
JMenuItem mi = new JMenuItem("Copy");
mi.setMnemonic("C");
mnemonic 속성은 setMnemonic() 메소드에 의해 설정된 글자에 밑줄을 표시한다. 이때 메뉴 아이템 문자열에 설정된 글자를 사용해야 하는 것을 기억하자. 그렇지 않으면 밑줄은 나타나지 않고 사용자는 키보드 단축키 작동 여부를 알 수 없을 것이다. 또한 밑줄 단축키 기능은 플랫폼과 L&F이 지원하지 않으면 무용지물이다.

SDK 1.4에서는 밑줄 단축키로 사용되고 있는 글자가 여럿 존재할 경우 원하는 글자에 밑줄 단축키를 만들기 위해 displayedMnemonicIndex을 사용할 수 있다. 예를 들어 Save As 메뉴 아이템에서는 소문자 a가 아닌 대문자 A에 밑줄 단축키를 만들기 위해 setDisplayedMnemonicIndex(int index)의 index 값에 5라는 인자를 넘겨 호출한다.

이미지

스윙에서는 메뉴 아이템에 아이콘을 포함시켜 좀더 명확하게 메뉴의 의미를 전달할 수 있다. JMenuItem 클래스 생성자에 다음과 같이 Icon 객체를 전달할 수 있다.
JMenu menu = new JMenu("Justify");

// 처음 2개의 아이템은 텍스트와 이미지를 가지고 있다.
// 3번째 것은 이미지만 가지고 있다. 
menu.add(new JMenuItem("Center", new ImageIcon("center.gif")));
menu.add(new JMenuItem("Right", new ImageIcon("right.gif")));
menu.add(new JMenuItem(new ImageIcon("left.gif")));
기본적으로 텍스트는 [그림 14-8]과 같이 이미지 좌측에 온다. 보는 것처럼 단일 이미지로 구성된 메뉴 아이템일 경우, 종종 이미지가 텍스트의 오른쪽에 오게 되는 잘못을 범하기도 한다. 이러한 문제를 해결하기 위해 setHorizontalTextAlignment() 메소드를 통해 텍스트와 이미지의 위치를 조절하여 좀더 자연스러운 메뉴를 만들게 해준다.
JMenu menu = new JMenu("Justify");
// 처음 두개의 아이템은 텍스트와 이미지를 가지고 있다.
// 세번째 것은 이미지만 가지고 있다. 텍스트는 오른쪽에 위치한다. 
JMenuItem item1= new JMenuItem("Center", new ImageIcon("center.gif")));
item1.setHorizontalTextAlignment(SwingConstants.RIGHT);
JMenuItem item2= new JMenuItem("Right", new ImageIcon("right.gif")));
item2.setHorizontalTextAlignment(SwingConstants.RIGHT);

// 메뉴에 메뉴 아이템을 붙인다.
menu.add(item1);
menu.add(item2);
menu.add(new JMenuItem(new ImageIcon("left.gif")));


[그림 14-8] 메뉴 아이템 내에 이미지와 텍스트 위치

[그림 14-8]과 같이 이미지 옆에 텍스트가 온다. 클래스 계층도를 따라 setHorizontalTextAlignment() 메소드를 살펴보면 AbstractButton 클래스가 있다. 이전에 언급했던 것처럼 JMenuItem은 텍스트와 이미지를 가지고 있는 버튼 객체이며 AbstractButton 클래스의 setVerticalTextAlignment() 메소드를 통해 이미지가 메뉴 아이템 텍스트 보다 클 경우에만 텍스트의 수직 위치를 조절할 수 있다. (메뉴 및 버튼 정렬에 대한 AbstractButton 클래스, OverlayLayout 클래스에 대해 알고 싶다면 각각 Chapter 5와 11을 참고) 만약 이후 챕터에 나오는 Action 객체를 통해 메뉴 아이템을 생성할 경우 이미지는 텍스트의 왼쪽에 오게 된다.

자바는 GIF파일의 "transparent" 색상을 명시하거나 특정한 픽셀 생상을 조절하는 색상 필터를 만듦으로 이미지를 투명하게 보여줄 수도 있다. 보통 전자가 더 쉽다.


Java Swing, 2nd Edition

참고 도서

Java Swing, 2nd Edition
David Wood, Marc Loy, James Elliott, Brian Cole, Robert Eckstein


이벤트 핸들링

메뉴 아이템의 이벤트를 처리하는 방법은 아주 다양하다. 메뉴 아이템이 AbstractButton으로부터 ActionEvent를 상속 받기 때문에 각각의 메뉴 아이템에 Action 명령을 할당하고 같은 ActionListener를 등록할 수 있다. (종종 자동적으로 같은 이름을 가진 컴포넌트가 된다.) 그런 다음 리스너의 actionPerformed() 메소드 안에서 이벤트를 발생시킨 메뉴 아이템의 action 명령을 얻기 위해 이벤트의 getActionCommand() 메소드를 사용한다. 이것은 리스너에게 어떤 메뉴 아이템이 선택되었는지 알려주며 그에 상응하는 반응을 할 수 있게끔 해준다. IntroExample.java, PopupMenuExample.java 예제에서 이러한 접근방법을 사용하고 있다.

ActionListener를 각각의 메뉴 아이템에 등록할 수도 있긴 하지만 어떤 메뉴 아이템이 선택되었는지에 대한 추측이 필요하게 된다. 스윙은 좀더 객체 지향적인 접근을 지원하는데 애플리케이션에서 각각의 작업과 일치하는 상세한 Action 객체를 생성하는 것이다. 이것은 한곳에서 action의 이름, 아이콘, 키스트로크(keystroke), 다른 속성에 대한 코드를 묶을 수 있는 것을 의미한다. 메뉴 아이템을 생성하기 위해 Action을 사용한다면 자동적으로 아이템의 텍스트, 이미지, 단축키를 사용할 수 있다.

이러한 기술은 툴바나 메뉴와 같은 다양한 방법으로 동일한 action을 실행시킬 때 유용하다. 메뉴 아이템과 툴바 버튼을 만들기 위해 동일한 Action 인스턴스를 사용할 수 있고 각각 적절한 이름과 외형을 가질 수도 있다. Action 인스턴스를 적절한 시기에 사용하려면 Action 인스턴스의 setEnabled를 호출함으로써 action과 관련된 메뉴와 툴바 버튼을 비활성화시키는 작업을 할 수 있다. 마찬가지로 action의 이름, 아이콘과 같은 속성들을 변경함으로써 관련된 메뉴 툴바와 같은 사용자 인터페이스 컴포넌트를 갱신할 수도 있다.

SDK 1.3 이전 버전이 Action으로부터 JMenuItem을 직접적으로 생성할 수는 없지만 Jmenu 또는 JPopupMenuAction을 추가함으로써 같은 효과를 내기 때문에 적절한 JMenuItem을 설정할 수 있다.

속성들

JMenuItem의 속성은 [표 14-4]에 나와있다. 대부분의 속성들은 재설정된 상위클래스의 속성들이다. borderPainted 속성은 항상 false 이며 이것은 border를 가지지 않는 것을 의미한다. focusPainted 속성 또한 포커스 사각형이 메뉴 아이템 주위로 그려지지 않도록 하기위해 항상 false이다. horizontalTextPosition, horizontalAlignmentJButton.LEFT 값으로 초기화 된다. 이것은 텍스트의 위치를 이미지 아이콘 왼쪽에 놓고 메뉴 아이템 왼쪽 위에 위치시킨다. 속성들을 재설정하는 방법들은 이전 예제에 설명되어 있다.

[표 14-4] JMenuItem 속성
속성 데이터 타입 get is set 디폴트 값
acceleratorb KeyStroke ·   · null
accessibleContexto Accessible Context ·     JMenuItem.AccessibleJMenuItem(  )
armedb, o boolean   · · false
borderPaintedo boolean   · · false
componento Component ·      
enabledo boolean   · · true
focusPaintedo boolean   · · false
horizontalAlignmento int ·   · JButton.LEFT
horizontalTextPositiono int ·   · JButton.LEFT
menuDragMouseListeners1.4 MenuDragMouseListener[ ] ·      
menuKeyListeners1.4 MenuKeyListener[ ] ·      
modelo ButtonModel ·   · DefaultButtonModel(  )
subElementso MenuElement[ ] ·      
UIb MenuItemUI     · From L&F
UIClassIDo String ·     "MenuItemUI"
1.4since 1.4, bbound, ooverridden
AbstractButton 클래스의 속성을 보려면 [표 5-4] 참조


accelerator 속성은 메뉴 아이템의 키보드 단축키를 설정하며 일반적으로 메뉴 아이템 문자열 오른쪽에 온다. armed 속성은 ButtonModel 모델의 상태를 조절하는 boolean 타입이다. 필요하다면 이것을 사용하여 프로그램적으로 메뉴 아이템을 선택할 수 있다. enabled 속성은 사용자가 메뉴 아이템을 선택했는지 여부를 가리는 boolean 타입이다. 만약 메뉴 아이템이 비활성화 되면 JMenuItem은 자동으로 텍스트와 이미지를 회색으로 만들어 버린다. 앞에서 언급했지만 메뉴 아이템을 조정하는 가장 좋은 방법은 자동으로 Action의 상태를 추적하는 Action 객체를 이용하는 방법이다. subElements 속성은 메뉴 아이템이 가지고 있는 서브 메뉴의 배열을 제공한다.

생성자
JMenuItem (  )
JMenuItem (Action action)
JMenuItem (Icon icon)
JMenuItem (String string)
JMenuItem (String string, Icon icon)
JMenuItem (String string, int mnemonic)
적절한 아이콘과 문자열로 메뉴 아이템을 생성할 수 있다. 또한 원하는 문자열을 밑줄 단축키로 만들 수도 있다. 버전 1.3 이후부터는 Action의 속성을 이용하여 JmenuItem의 속성에 직접 접근할 수 있다.

이벤트

JmenuItems는 다양한 이벤트를 가지고 있다. 아마 가장 중요한 것은 아이템이 선택되었을 때 발생하는 ActionEvents일 것이다. 이러한 이벤트를 위해 리스너(listener)를 추가/삭제하는 메소드는 AbstractButton으로부터 상속받는다. 또한 JMenuItems는 메뉴 상단에 위치하는 키의 눌림과 마우스 움직임을 위해서 MenuDragMouseEvent, MenuKeyEvent와 같은 특별한 이벤트를 사용한다. 이러한 이벤트에서 리스너를 등록하기 위한 메소드는 다음과 같다.
addMenuDragMouseListener (MenuDragMouseListener 1)
removeMenuDragMouseListener (MenuDragMouseListener 1)
이것들은 MenuDragMouseEvent와 관련 있는 특정한 MenuDragMouseListener를 추가/삭제하는 기능을 가지고 있다.
addMenuKeyListener (MenuKeyListener 1)
removeMenuKeyListener (MenuKeyListener 1)
이러한 메소드들은 MenuKeyEvent와 관련 있는 특정한 MenuKeyListener를 추가/삭제하는 기능을 가지고 있다.

다음 메소드들은 비록 사용자가 호출하지 않더라도 이벤트 발생을 지원한다.
public void processMenuDragMouseEvent (MenuDragMouseEvent e)
MouseEvent 타입의 기반을 둔 MenuDragMouseEvent가 발생하게 된다. 만약 MouseEventMOUSE_ENTERED라면 fireMenuDragMouseEntered() 메소드를 발생시키게 된다.
public void processMenuKeyEvent (MenuKeyEvent e)
MenuKeyEvent 타입의 기반을 둔 MenuKeyEvent가 발생하게 된다. 만약 MenuKeyEventKEY_RELEASED라면 fireMenuKeyReleased() 메소드를 발생시키게 된다.

메소드
public void updateUI()
현재 UI 매니저가 컴포넌트의 대리자를 초기화 함으로서 컴포넌트의 L&F이 갱신된다.

메뉴 요소(element) 인터페이스
public void menuSelectionChanged(boolean isIncluded)
public MenuElement[ ] getSubElements(  )
public Component getComponent(  )
public void processMouseEvent(MouseEvent event, 
   MenuElement path[ ], MenuSelectionManager manager)
public void processKeyEvent(KeyEvent event, MenuElement path[ ], 
   MenuSelectionManager manager)
MenuElement 인터페이스에 대해서는 다음에 논의하겠다.

MenuDragMouseEvent 클래스 스윙은 마우스가 메뉴위에서 드래그되면 일련의 이벤트를 생성해낸다. MenuDragMouseEvent는 특정한 메뉴 아이템과 연관된 드래그를 나타낸다. MenuDragMouseListener를 상속한 객체를 JMenuItem의 메소드 addMenuDragMouseListener()를 사용하여 이러한 이벤트를 감지할 수 있다. MenuDragMouseListener를 상속한 객체는 메뉴내의 마우스 드래그 응답에 반응할 수 있는 4개의 분리된 메소드를 가지고 있다. 각각의 메소드는 드래그가 어떤 반응을 나타내는지 보여준다. [표 14-5]는 MenuDragMouseEvent의 속성들을 보여주고 있다.

속성들

[표 14-5] MenuDragMouseEvent 속성
속성 데이터 타입 get is set 디폴트 값
clickCounto int ·      
ido int ·   ·  
manager MenuSelectionManager ·      
modifierso Object ·   ·  
path MenuElement[ ] ·      
popupTriggero boolean   ·    
source Object ·      
wheno long ·      
xo int ·      
yo int ·   ·  
ooverridden
java.awt.event.MouseEvent 참고.


이벤트에 대한 기본값은 존재하지 않고 모든 속성들은 생성자 안에 설정되어 있다. source 속성은 이벤트를 보내는 객체를 나타낸다. id 속성은 발생하는 이벤트의 타입을 설명하고 있다. when 속성은 이벤트 발생시간을 리턴한다. Modifiers 속성은 Alt, Ctrl, Shift, 복합키 뿐만 아니라 마우스의 어떠한 버튼이 선택되었는지를 알려주는 다양한 mask를 테스트하게 해준다. x, y 속성은 현재 컴포넌트와 관련된 마우스 포인터의 현재 위치를 반환한다. clickCount 속성은 드래그에 앞선 마우스 클릭 횟수를 나타낸다. popupTrigger 속성은 팝업 메뉴의 발생여부를 알린다. path 속성은 MenuElement 객체의 순차적인 배열을 특정한 메뉴의 위치와 함께 반환한다. 마지막으로 manager 속성은 현재의 메뉴 시스템을 위한 MenuSelectionManager의 참조자를 가지고 있다.

생성자
public MenuDragMouseEvent(Component source, int id, long when, int modifiers, 
                          int x, int y, int clickCount, boolean popupTrigger, 
                          MenuElement[ ] path, MenuSelectionManager manager)
[표 14-5]에 있는 모든 속성들은 특정한 값으로 초기화해야 한다.

MenuDragMouseListener 인터페이스

MenuDragMouseEvent 객체를 받는 MenuDragMouseListener 인터페이스는 4개의 메소드를 가지고 있다. 첫번째 메소드는 메뉴 아이템 안에서 마우스가 드래그 되었을 때 실행되며 두 번째는 메뉴 아이템 안에서 마우스를 클릭하면 실행된다. 나머지 두 개의 메소드는 마우스가 드래그를 시작하여 메뉴 아이템으로 진입하거나 벗어날 때 실행된다.

메소드들
public abstract void menuDragMouseDragged(PopupMenuEvent e)
메뉴 아이템 내에서 마우스가 드래그 되어질 때 발생.
public abstract void menuDragMouseReleased(PopupMenuEvent e)
메뉴 아이템 내에서 마우스의 버튼이 놓여질 때 발생.
public abstract void menuDragMouseEntered(PopupMenuEvent e)
마우스가 드래그 되면서 메뉴 아이템으로 진입 될 때 발생.
public abstract void menuDragMouseExited(PopupMenuEvent e)
마우스가 드래그 되면서 메뉴 아이템에서 벗어날 때 발생.

MenuKeyEvent 클래스

스윙은 특정한 메뉴 아이템이 키 이벤트를 받을 때 이벤트를 발생시킨다. 키 이벤트는 특정한 메뉴로 직접적으로 전달되지는 않지만 메뉴 아이템은 메뉴가 화면에 팝업되는 동안 키 이벤트에 응답한다. JmenuItemaddMenuKeyListener() 메소드를 통해 MenuKeyListener를 상속한 객체를 추가함으로써 이러한 이벤트를 처리할 수 있다. MenuKeyListener를 상속한 객체는 메뉴 키 이벤트가 발생했을 때 이를 처리하는 3개의 메소드를 가질 수 있다. [표 14-6]은 MenuKeyEvent의 속성들을 보여주고 있다. 이벤트에 대한 기본값은 존재하지 않고 모든 속성들은 생성자 안에 설정되어 있다. source 속성은 이벤트를 보내는 객체를 나타낸다. id 속성은 발생하는 이벤트의 타입을 설명하고 있다. when 속성은 이벤트 발생시간을 반환한다. Modifiers 속성은 Alt, Ctrl, Shift, 복합키 뿐만 아니라 마우스의 어떠한 버튼이 선택되었지 알기 위한 다양한 mask를 테스트하게 해준다. keyCodekeyChar 속성은 눌려진 키를 나타낸다. path 속성은 MenuElement 객체의 정렬된 배열을 특정한 메뉴의 위치와 함께 반환한다. 마지막으로 manager 속성은 현재의 메뉴 시스템을 위한 MenuSelectionManager의 참조자를 가지고 있다.

[표 14-6] MenuKeyEvent 속성
속성 데이터 타입 get is set 디폴트 값
ido int ·   ·  
keyCharo char ·   ·  
keyCodeo int ·      
manager MenuSelectionManager ·      
modifierso Object ·   ·  
path MenuElement[ ] ·      
source Object ·      
wheno long ·      
ooverridden
java.awt.event.keyEvent 참고.


생성자
public MenuDragMouseEvent(Component source, int id, long when, 
	int keyCode, char keyChar, MenuElement[ ] path, MenuSelectionManager manager)
생성자는 [표 14-6]에 설명되어 있는 속성들을 가지고 있다.

MenuKeyListener 인터페이스

MenuKeyEvent 객체를 받는 MenuKeyListener 인터페이스는 3개의 메소드를 가지고 있다.

첫번째 메소드는 키가 눌리거나 놓일 때 호출되며 두 번째는 키가 눌릴 때 발생한다. 마지막은 키가 놓인 후에 호출된다. 키가 눌려지거나 몇 초 동안 누르고 있다면 스윙은 키가 항상 눌려진 것으로 생각한다.

메소드
public abstract void menuKeyTyped(MenuKeyEvent e)
메뉴 요소를 위한 키가 눌려지거나 놓일 때 호출된다.
public abstract void menuKeyPressed(MenuKeyEvent e)
메뉴 요소를 위한 키가 눌려질 때 호출된다.
public abstract void menuKeyReleased(MenuKeyEvent e)
메뉴 요소를 위한 키가 놓일 때 호출된다.

메뉴 아이템 자체는 독립적으로 존재할 수 없으므로 반드시 메뉴안에 포함되어 있어야 한다. 스윙은 고정 메뉴나 팝업 메뉴와 같은 2가지 메뉴를 제공하며 JMenuJPopupMenu 클래스를 사용하여 2가지 메뉴를 사용할 수 있다.

다음 기사에서는 JPopupMenu 클래스에 대해 살펴볼 것이다.
TAG :
댓글 입력
자료실

최근 본 책0