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

한빛출판네트워크

IT/모바일

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

한빛미디어

|

2003-05-27

|

by HANBIT

17,205

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

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


이전기사 보기


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


JMenu 클래스

Jmenu 클래스는 JmenuBar 또는 다른 Jmenu에 속해 있는 고정된 메뉴를 표현한다. 메뉴는 최상위 메뉴라 불리는 메뉴 바에 직접적으로 속해 있다. 반면에 하위 메뉴는 메뉴 바에 직접 속해 있지 않고 메뉴 제목을 나타내는 메뉴 아이템에 포함된다. 이런 메뉴 아이템은 일반적으로 사용자가 선택한 메뉴를 가리키는 오른쪽 화살표로 표시되어 있다. [그림 14-11]을 보자.


[그림 14-11] 최상위 메뉴와 하위 메뉴

JMenu는 특이한 클래스이다. MenuUI 대리자(delegate)를 포함하고 있지만 데이터 모델을 위해서는 ButtonModel을 사용하고 있다. 두 개의 컴포넌트(메뉴 아이템, 팝업 메뉴)를 통해 좀더 자세히 살펴보자. 메뉴 아이템이 가지고 있는 타이틀을 선택하면 메뉴를 아래로 혹은 오른쪽에 보여주기 위해서 팝업 메뉴에게 신호를 보낸다. JMenu 는 실제로 메뉴의 타이틀 부분을 실행 가능케 하는 JMenuItem 클래스를 상속 받고 있다. 이것은 사실상 메뉴를 버튼처럼 만드는 것이다. 몇몇 플랫폼에서는 JMenuItem 상위 클래스의 mnemonic 속성을 사용함으로 메뉴 타이틀의 밑줄 단축키를 정의할 수도 있다. 게다가 JMenuItemenabled 속성을 가지고 메뉴를 비활성화 할 수도 있다.

팝업 메뉴에서는 add( ), insert( ) 메소드들을 호출함으로서 메뉴의 팝업 부분에 JMenuItem, Component 또는 Action 객체들을 추가하거나 삽입할 수 있다. JMenu는 내부적으로 동등한 JMenuItem 객체를 만들기 때문에 메뉴에 간단한 문자열을 추가할 수도 있다. 클래스는 각각의 메뉴 아이템에 정수형의 인덱스를 할당하고 레이아웃 매니저에 기반을 두고 정렬시킨다. 또한 addSeparator( ) 메소드를 사용해서 메뉴의 구분자를 추가할 수도 있다.

주의: 키보드 단축키는 단순히 선택된 메뉴를 화면에 보여주려는 것이 아니라 실제 프로그램 실행을 발생시키기 때문에 JMenu 객체(최상위, 하위메뉴)에는 키보드 단축키를 사용할 수 없다. 몇몇 플랫폼에서는 메뉴를 선택하기 위해 메소드를 사용할 수 있긴 하지만 모두 안전한 방법은 아니기 때문에 서브 메뉴가 아닌 JMenuItems에 키보드 단축키를 할당해야 한다.

프로그래밍을 통해서 popupMenuVisible 속성을 true로 설정하여 화면에 서브 메뉴를 보여줄 수도 있다. 메뉴 타이틀 버튼이 없다면 서브 메뉴가 보이지 않는다는 것을 알아두자.

[그림 14-12] 는 JMenu 컴포넌트의 클래스 다이어그램 이다.


[그림 14-12] JMenu 클래스 다이어그램

속성

JMenu 속성은 [표 14-8]과 같다. JMenu는 메뉴 아이템들의 리스트를 표현하기 위해 JPopupMenu를 사용한다. 다른 메뉴에 접근하고 싶다면 popupMenu 속성을 사용하면 된다. popupMenuVisible 속성은 메뉴 부분이 현재의 화면에 출력 되는지를 나타낸다. 이속성이 true라면 타이틀 버튼이 보일 때 메뉴가 나타난다. 또한 사용자가 메뉴 버튼을 선택했는지를 나타내주는 selected 속성을 가지고 있다. 두 속성은 서로를 반영하고 있다.



[표 14-8] JMenu 속성
속성 데이터 타입 get is set 디폴트 값
accessibleContexto Accessible Context ·     JMenu.accessibleJMenu(  )
component Component ·      
componentOrientation1.4, o ComponentOrientation ·   · From L&F
delay int ·   · 0
itemCount int ·     0
itemi JMenuItem ·     null
layouto LayoutManager ·   · OverlayLayout(  )
menuComponentCount int ·     0
menuComponenti Component ·     null
menuComponents Component[ ] ·      
menuListeners1.4 MenuListener[ ] ·      
modelo ButtonModel ·   · DefaultButtonModel(  )
popupMenu JPopupMenu ·      
popupMenuVisible boolean   · · false
selected boolean   · · false
subElements MenuElement[ ] ·      
tearOffu boolean   ·   Throws an Error
topLevelMenub, o boolean   ·    
UIb MenuUI     · From L&F
UIClassID String ·     "MenuUI"

1.4since 1.4, bbound, iindexed, ooverridden, uunimplemented
JMenuItem 클래스를 보려면 [표14-4] 참조.



topLevelMenu 속성은 JMenu가 메뉴 바에 직접 속해있거나 서브 메뉴가 아닐 경우, true 값을 가진다. item은 메뉴 내 각각의 JMenuItem 객체에 접근할 수 있는 인덱스된 속성이다. ItemCount는 화면에 보여지는 모든 JMenuItem 객체의 개수를 가지고 있는 속성이다. delay 속성은 메뉴가 화면에 보여지거나 사라지게 하는 이벤트를 받은 후에 메뉴가 기다리고 있는 시간(단위: 천분의 일초)의 합이다. 이 속성은 반드시 양의 값을 가져야 한다. 그렇지 않으면 setDelay( )가 IllegalArgumentException을 발생 시켜야 한다.

menuComponent 속성은 좀더 일반화된 item 속성이다. 그것은 JMenuItem 보다는 Component에 할당된 인덱스의 컴포넌트를 반환한다. menuComponentCount 속성은 메뉴 아이템, 구분자, 현재 메뉴에 있는 다른 컴포넌트의 개수를 반환한다. menuComponents 속성은 메뉴 내 아이템들 각각에 접근할 수 있는 Component 객체의 배열을 반환한다.

componentOrientation 속성은 사용언어 문자가 왼쪽에서 오른쪽으로 진행되지 않는 비서구권 언어들도 사용할 수 있게 해준다. JMenu는 메뉴가 사용하고 있는 JPopupMenu 대리자에게 적절한 변경을 전달하기 위해 이 속성을 오버라이드한다.

주의: tearOff 속성은 아직 작동하진 않지만 향후 스윙에서 사용할 목적으로 예약되어 있다. 지금 사용할 경우, UnsupportedOperationException과 같은 Error를 발생시킬 것이다. Error는 자바 VM의 치명적인 오류이기 때문에 이 속성을 사용한다면 해당 애플리케이션에 문제가 발생할 수도 있다.

생성자
public JMenu(  )
public JMenu(Action a)
public JMenu(String s)
public JMenu(String s, boolean b) 
기본적인 JMenu를 초기화 한다. Action을 메뉴와 연결하거나 tearOff 속성을 위한 boolean 값 뿐만 아니라 메뉴에 나타나는 특정한 문자열을 사용할 수도 있다.

메뉴 아이템
public JMenuItem add(JMenuItem menuItem)
public Component add(Component c) 
public void add(String s)
public JMenuItem add(Action a)
메뉴에 다양한 요소들을 추가할 수 있다. JMenuItemJComponent 객체들이 추가될 수 있지만 MenuElement 인터페이스를 상속 받았다면 후자의 방법이 더 좋다. 인자로 String 값을 주면 해당 문자열을 가지는 메뉴 아이템이 생성된다. Action을 설정하면 해당 JMenuItem를 얻기 위해 Action의 문자와 아이콘 속성이 사용되며 아이콘 오른쪽에 문자열이 나타난다. 설정된 것은 Action에 관한 연결을 가지고 있고 속성들의 변화를 반영하기 위해 갱신된다. 결과적으로 JMenuItem이 반환되고 포맷을 변경할 수 있다.
public void addSeparator(  )
메뉴에 구분자를 추가할 수 있다. 보통 구분자는 메뉴를 가로지르는 단일 수평선으로 구성되어 있다.
public void insert(String s, int index)
public JMenuItem insert(JMenuItem mi, int index)
public JMenuItem insert(Action a, int index)
특정 인덱스에 메뉴 아이템을 삽입한다. 인덱스 값은 반드시 양수가 되거나 메소드를 사용할 때 IllegalArgumentException 예외를 발생시켜야 하며 JMenuItem, String, 또는 Action을 사용할 수 있다. 인자로 String 값을 주면 해당 문자열을 가지는 메뉴 아이템이 생성된다. Action을 설정하면 해당 JMenuItem를 얻기 위해 Action의 문자와 아이콘 속성이 사용되며 아이콘 오른쪽에 문자열이 나타난다. 설정된 것은 Action에 관한 연결을 가지고 있고 속성들의 변화를 반영하기 위해 갱신된다. 결과적으로 JMenuItem이 반환되고 포맷에 대해 변경을 가할 수 있다. 모든 메뉴 아이템의 인덱스들은 하나씩 증가하고 특정한 위치를 나타낸다.
public void insertSeparator(int index)
특정 인덱스 위치에 수평 구분자를 삽입한다. 인덱스가 양의 값이 아니면 IllegalArgumentException을 발생시킨다. 모든 메뉴 아이템의 인덱스들은 하나씩 증가하고 특정한 위치를 나타낸다.
public void remove(JMenuItem item)
public void remove(int index)
특정 인덱스를 나타내는 메뉴 아이템과 변수 JMenuItem과 일치하는 메뉴 아이템을 제거한다. 만약 일치하지 않는다면 메뉴에 아무런 변화도 일어나지 않는다. 메소드가 제대로 작동한다면 특정 인덱스 이후의 메뉴 아이템의 인덱스들은 하나씩 감소한다.
public void removeAll(  )
메뉴로부터 모든 아이템을 제거한다.

기타
public void updateUI(  )
기본 사용자 인터페이스 매니저를 강제로 갱신하여 새로운 MenuUI를 나타내기 위한 대리자(delegate)를 초기화 한다.
public void setMenuLocation(int x, int y)
화면에 보이는 메뉴의 위치를 설정한다.
public boolean isMenuComponent(Component c)
현재 메뉴에서 컴포넌트 c의 존재 여부를 나타낸다. 이 메소드는 모든 하위메뉴를 검색한다.
public String paramString(  )
메뉴 속성의 디버깅을 위해 현재 상태를 나타내는 String을 반환한다.

이벤트

JMenu 객체는 사용자가 메뉴 타이틀 버튼을 선택할 때 MenuEvent를 발생시킨다. JMenu 객체는 MenuEvent 구독자 리스트를 유지하기 위한 표준 메소드 addChangeListener( ), removeChangeListener( )를 가지고 있다.
public void addMenuListener(MenuListener listener)
public void removeMenuListener(MenuListener listener) 
메뉴의 이벤트를 받는 리스너 리스트로부터 MenuListener를 제거하거나 추가한다.

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


Java Swing, 2nd Edition

참고 도서

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


메뉴 예제

아래는 JMenu 클래스 사용 예제 프로그램이다. 메뉴 이벤트를 처리하기 위해서 스윙의 Action 클래스를 사용하였다. (다음 챕터에서는 툴바를 사용한 작업을 보여줄 것이다.)
//  MenuExample.java
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class MenuExample extends JPanel {

    public JTextPane pane;
    public JMenuBar menuBar;

    public MenuExample(  ) {
        menuBar = new JMenuBar(  );
        JMenu formatMenu = new JMenu("Justify");
        formatMenu.setMnemonic("J");

        MenuAction leftJustifyAction = new MenuAction("Left", 
                                       new ImageIcon("left.gif"));
        MenuAction rightJustifyAction = new MenuAction("Right",
                                        new ImageIcon("right.gif"));
        MenuAction centerJustifyAction = new MenuAction("Center",
                                         new ImageIcon("center.gif"));
        MenuAction fullJustifyAction = new MenuAction("Full",
                                       new ImageIcon("full.gif"));

        JMenuItem item;
        item = formatMenu.add(leftJustifyAction);
        item.setMnemonic("L");
        item = formatMenu.add(rightJustifyAction);
        item.setMnemonic("R");
        item = formatMenu.add(centerJustifyAction);
        item.setMnemonic("C");
        item = formatMenu.add(fullJustifyAction);
        item.setMnemonic("F");

        menuBar.add(formatMenu);
        menuBar.setBorder(new BevelBorder(BevelBorder.RAISED));

    }

    class MenuAction extends AbstractAction {

        public MenuAction(String text, Icon icon) {
            super(text,icon);
        }

        public void actionPerformed(ActionEvent e) {
            try { pane.getStyledDocument(  ).insertString(0 ,
                  "Action ["+e.getActionCommand(  )+"] performed!\n", null);
            } catch (Exception ex) { ex.printStackTrace(  ); } 
        }
    }

    public static void main(String s[ ]) {

        MenuExample example = new MenuExample(  );
        example.pane = new JTextPane(  );
        example.pane.setPreferredSize(new Dimension(250, 250));
        example.pane.setBorder(new BevelBorder(BevelBorder.LOWERED));

        JFrame frame = new JFrame("Menu Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(example.menuBar);
        frame.getContentPane(  ).add(example.pane, BorderLayout.CENTER);
        frame.pack(  );
        frame.setVisible(true);
    }
}
모든 Action은 내부 클래스의 MenuAction 인스턴스이다. 메뉴에 해당하는 각각의 Action을 추가하기 때문에 이미지가 왼쪽에 오는 적당한 JMenuItem을 생성한다. 이것은 원하는 방법으로 메뉴의 결과를 조절할 수 있게 해주며, 메뉴 아이템의 밑줄 단축키를 만들 수 있다. 플랫폼이 밑줄 단축키를 지원하면 다양한 플랫폼 위에서 이 프로그램을 사용할 수 있는 장점이 있다. 그렇지만 단순히 다양한 플랫폼 지원을 위해 사용자 인터페이스 부분에 밑줄 단축키를 의지하는 것은 좋지 않다(사실 모든 플랫폼이 지원하지 않는다면 사용하지 않는 것이 더 좋다).

[그림 14-13]과 같이 예제는 단일 메뉴에 하나의 메뉴 바를 가지고 있다. 메뉴는 4개의 메뉴 아이템을 포함하고 있고 앞서 본 팝업 메뉴 예제와 비슷하다. 사용자가 메뉴 아이템을 선택하면 스윙은 우리가 만든 MenuAction 클래스 안에 actionPerformed( )메소드를 실행시키는 ActionEvent을 발생시킨다. 이전 예제와 같이 메뉴아이템 내용이 화면에 출력된다. 출력 결과를 위해 메뉴 선택 내용의 결과를 도스 화면 출력보다 화면에 출력하기 위해 간단한 JTextPane를 추가 시켰다. JTextPane에 대한 좀더 자세한 내용은 챕터 19와 22를 참고하면 된다.


[그림 14-13] 밑줄 단축키와 아이콘이 있는 메뉴 아이템

MenuEvent 클래스

특정 메뉴가 보여지거나 선택, 취소 될 때 리스너에게 알리는 간단한 이벤트이다. 그러나 이러한 이벤트가 반드시 하나씩만 발생하는 것은 아니다. 리스너는 3개의 개별적인 메소드를 정의해서 정확히 이벤트를 전달한다.

생성자
public MenuEvent(Object source)
생성자는 이벤트를 발생시키는 객체의 참조자를 가지고 있다.

MenuListener 인터페이스

MenuEvent를 받기 위한 연결고리인 MenuListener 인터페이스는 3개의 메소드를 상세화 한다. 처음 메소드는 메뉴가 취소될 때 호출되며 나머지 2개의 메소드는 메뉴가 선택될 때 호출된다. 메뉴 객체에 발생한 이벤트를 알고 싶은 리스너 객체는 반드시 이 인터페이스를 상속해야 한다.

메소드
public abstract void menuCanceled(MenuEvent e)
메뉴가 취소되거나 화면으로부터 사라졌을 때 발생한다.
public abstract void menuDeselected(MenuEvent e)
특정 메뉴의 타이틀 버튼이 선택해제 되었을 때 발생한다.
public abstract void menuSelected(MenuEvent e)
특정 메뉴의 타이틀 버튼이 선택되었을 때 발생한다.

다음 기사에서는 선택 가능한 메뉴 아이템(라디오,체크박스)에 대해 살펴볼 예정이다.
TAG :
댓글 입력
자료실

최근 본 상품0