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

한빛출판네트워크

IT/모바일

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

한빛미디어

|

2003-05-15

|

by HANBIT

13,530

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

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


이전기사 보기


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

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

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


JPopupMenu 클래스

팝업 메뉴는 UI(user-interface)에서 점차적으로 많이 사용되고 있다. 팝업 메뉴는 invoker라 불리는 컴포넌트에 연관되어 있고 메뉴 바에 종속되지 않기 때문에 어느 위치에서나 나타날 수 있다. 뿐만 아니라 특정 인터페이스 요소와 연결되어 있기 때문에 팝업 메뉴는 상당히 context에 민감하다. 팝업 메뉴는 마우스가 invoking 컴포넌트 위에 있을 때 발생하는 플랫폼 종속적인 트리거 이벤트에 의해 보여진다. AWT와 스윙에서 이런 트리거는 보통 마우스 이벤트이며 한번 이벤트가 발생하면 사용자는 메뉴와 상호작용 할 수 있다. [그림 14-9]는 스윙에서 팝업 메뉴를 보여주고 있다.


[그림 14-9] 스윙에서 팝업 메뉴

add()insert() 메소드를 이용하여 팝업 메뉴에 JMenuItem, Component, Action 객체를 추가하거나 삽입할 수 있다. JPopupMenu 클래스는 정수 인덱스 값을 메뉴 아이템에 할당하고 팝업 메뉴 레이아웃 매니저에 기초하여 순서대로 정렬시킬 뿐만 아니라 addSeparator() 메소드를 사용하여 팝업 메뉴에 구분자를 추가할 수도 있다. 물론, 이 구분자도 하나의 인덱스를 할당 받는다. [그림 14-10]은 JPopupMenu 컴포넌트의 클래스 다이어그램을 보여주고 있다. 이 클래스는 ToolTip과 같은 간단한 정보를 나타내는 용도로도 사용될 수 있다.


[그림 14-10] JPopupMenu 클래스 다이어그램

팝업 메뉴 화면에 보여주기

팝업 메뉴는 보통 플랫폼 종속적인 트리거에 의해 발생되는 show() 메소드를 통해 화면에 보여진다. show() 메소드는 팝업 메뉴가 나타나기 전에 locationinvoker 속성값을 정할 수 있다. 팝업 메뉴는 다양한 이벤트 즉, 메뉴 아이템을 선택, 창의 크기를 조정, 최소화 및 최대화 또는 팝업 메뉴가 속해있는 창을 닫을 때 자동으로 사라진다. (팝업 메뉴가 사라지는 것에 대해서는 걱정할 필요가 없다.) 팝업 메뉴를 보여주고 싶다면 모든 MouseEvents를 조사하여 팝업 트리거가 발생한 적절한 시점에 화면에 보여주면 된다. 좀더 자세히 말하면 MouseEvent가 팝업 트리거라면 상위 클래스에 이벤트를 전달하지 말아야 한다. 왜냐하면 스윙은 팝업 메뉴가 나타나는 즉시 취소 시켜 화면에서 사라지게 하기 때문이다. 가장 쉬운 방법은 모든 마우스 이벤트를 검사하는 것이다. 다음은 적당한 트리거를 받으면 팝업 메뉴를 화면에 나타내는 processMouseEvent() 메소드 이다.
public void processMouseEvent(MouseEvent e) {
    if (e.isPopupTrigger(  )) {
        popup.show(this, e.getX(  ), e.getY(  ));
    }
    else {
        super.processMouseEvent(e); 
    }
}
마우스 이벤트가 팝업 트리거인지 아닌지 체크하는 java.awt.event.MouseEventisPopupTrigger()와 같은 플랫폼 독립적인 방법의 사용을 주의해서 살펴보기 바란다. SDK 1.3이후부터 JPopupMenu는 같은 방식으로 사용할 수 있는 동등한 메소드를 제공하고 있다.

마우스가 컴포넌트 밖으로 벗어나면 스윙은 더 이상 팝업 트리거를 해당 컴포넌트에 전달하지 않으며 팝업 메뉴를 화면에 나타내지 않는다. 이것은 컴포넌트가 여러 개 있을 때 다양한 팝업 메뉴를 사용할 수 있다는 것을 의미한다.

속성

JPopupMenu 클래스의 속성은 [표 14-7]을 참고하면 된다. 팝업 메뉴는 다양한 속성을 가지고 있다. visible 속성은 팝업 메뉴가 현재 화면에 보이는가를 나타내며 setVisible() 메소드를 가지고 팝업 메뉴를 화면에 나타낼 수도 있다. 보통은 show() 메소드를 이용하는 것이 더 쉽다. location 속성은 팝업 메뉴의 위치를 조절한다. 읽기 전용인 margin 속성은 팝업 윈도우 경계의 공간을 조절하고 개별적인 메뉴 아이템을 둘러싸고 있는 가상의 사각형을 조절한다.

[표 14-7] JPopupMenu 속성
속성 데이터 타입 get is set 디폴트 값
accessibleContexto Accessible Context ·     JMenuItem.AccessibleJMenuItem(  )
borderPaintedo boolean   · · true
component Component ·      
componentAtIndexi Component ·      
invoker Component ·   ·  
labelb String ·   · ""
layouto LayoutManager ·   · GridBagLayout( )
lightWeightPopupEnabled boolean   · · getDefaultLightWeightPop-upEnabled( )
locationo Point     ·  
margin Insets ·      
popupMenuListeners1.4 PopupMenuListener[ ] ·      
popupSize Dimension     ·  
selectionModel SingleSelectionModel ·     DefaultSingleSelectionMo-del( )
subElements MenuElement[ ] ·      
UIb PopupMenuUI ·   · BasicPopupMenuUI( )
UIClassIDo String ·     "PopupMenuUI"
visibleb, o boolean   · · false

1.4since 1.4, bbound, iindexed, ooverridden
JMenuItem 클래스의 속성을 보려면 [표 14-4] 참조.



invoker 속성은 팝업 메뉴를 가지고있는 컴포넌트의 레퍼런스이다. borderPainted 속성은 팝업 메뉴 경계선의 색칠 여부를 나타낸다. 속성은 각각의 팝업 메뉴에 대해 특정한 라벨을 줄 수 있다. 라벨은 String이어야 하지만 특정 인덱스 값의 컴포넌트를 리턴하는 인덱스화된 속성값인 Jlabel. ComponentAtIndex는 아니다.

lightWeightPopupEnabled 속성은 프로그래머가 팝업 메뉴를 표현할 때 경량 컴포넌트의 사용 여부를 나타낸다. 만약 이 속성이 true라면 스윙은 팝업 메뉴가 상위 컴포넌트 드로잉 영역에 포함될 때 경량 컴포넌트를 사용하게 되고 영역에서 벗어나면 중량 컴포넌트를 사용하게 된다. 중량 컴포넌트를 사용하게 되면 이 속성을 off시켜야 한다. static 속성인 setDefaultLightWeightPopupEnabled() 메소드를 이용하여 모든 팝업 메뉴를 위한 속성을 기본값으로 초기화할 수 있다.


Java Swing, 2nd Edition

참고 도서

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


이벤트

JpopupMenu 객체는 팝업 메뉴가 보여지거나 사라질 때, 팝업 메뉴 아이템이 선택되지 않고 취소될 때 PopupMenuEvent를 발생 시킨다. 그리고 PopupMenuEvent의 리스트를 유지하기 위해 addPopupMenuListener()와 removePopupMenuListener() 메소드를 포함하고 있다.
public void addPopupMenuListener(PopupMenuListener l)
public void removePopupMenuListener(PopupMenuListener l)
객체 이벤트 큐(Queue)로부터 PopupMenuListener를 추가하거나 삭제 할 수 있다.

팝업 메뉴가 화면에 보여지기 전에 미리 통보 받을 수 있다는 기능은 애플리케이션에 기반한 메뉴의 내용과 상태를 조절할 수 있는 기회를 갖는 다는 것을 의미한다.

팝업 메뉴가 취소되면 메뉴는 보이지 않게 되고 두 개의 이벤트가 잠재적으로 발생된다. 취소 이벤트 자체는 빈번하게 사용되지는 않는다. 메뉴가 언제 화면에서 사라졌는지 알고 싶다면 popupMenuWillBecomeInvisible 핸들러를 사용하면 된다.

생성자
public JPopupMenu( )
public JPopupMenu(String title)
첫 번째는 메뉴 타이틀이 없는 팝업 메뉴를 생성하고 그 다음 것은 메뉴 타이틀을 위해 String 을 사용할 수 있다.

메뉴 아이템
public JMenuItem add(JMenuItem menuItem)
public Component add(Component c)
public JMenuItem add(Action a)
다양한 요소들을 팝업 메뉴에 추가할 수 있다. JmenuItem 또는 Jcomponent 중에 하나를 상속 받은 객체는 팝업 메뉴에 추가될 수 있다. 만약 MenuElement 인터페이스를 상속 받았다면 가장 후자의 기능을 이용하는 것이 좋다. 만약 Action을 명시하면 JmenuItem의 많은 속성을 사용할 수 있고 텍스트는 이미지 아이콘의 오른쪽에 오게된다. 또한 메뉴 아이템은 이름, 아이콘, 상태의 변경을 갱신 하기 위한 Action과 관계를 지속하며 그 결과 JmenuItem이 리턴되고 이것을 통해 메뉴 아이템 포맷을 변경할 수 있다.
public JMenuItem insert(Action a, int index)
public Component insert(Component component, int index)
JComponent 또는 Action을 이용하여 특정 인덱스에 특정한 메뉴 아이템을 추가할 수도 있다. MenuElement 인터페이스를 상속 받고 Jcomponent를 사용하는 것이 가장 좋다. Action을 명시하면 JmenuItem의 많은 속성을 사용할 수 있고 텍스트는 이미지 아이콘의 오른쪽에 오기 때문이다. 또한 메뉴 아이템은 이름, 아이콘, 상태의 변경을 갱신 하기 위한 Action과 관계를 지속하며 그 결과 JmenuItem이 리턴되고 이것을 통해 메뉴 아이템 포맷을 변경할 수 있다. 특정한 위치 이전이나 이후에 있는 모든 메뉴 아이템의 인덱스들은 증가된다.
public void addSeparator( )
팝업 메뉴에 구분자를 추가할 수 있다. 일반적으로 구분자는 메뉴 내 수평선으로 표현된다. 주의할 것은 메뉴 아이템과 마찬가지로 구분자에 인덱스가 할당된다는 것이다. 구분자는 표준 Jseparator와 다르게 내부(inner) 클래스의 인스턴스로 사용되고 항상 수평선이다.

화면에 나타내기
public void show(Component invoker, int x, int y)
팝업 메뉴를 원하는 좌표에 오도록 할 수 있다. 이 메소드는 invoking 컴포넌트에 레퍼런스를 갖고 있으며 setInvoker( ), setLocation( ), setVisible( )와 동일한 기능을 수행한다.
public void setPopupSize(int width, int height)
팝업 메뉴의 크기를 조절할 수 있는 두 가지 방법 중 한가지이다. 나머지 하나는 Dimension을 취하는 popupSize 속성이다.

기타
public int getComponentIndex(Component c)
컴포넌트 레퍼런스 c에 연관된 인덱스를 리턴한다. 만약 연관되는 컴포넌트가 없을 경우 -1을 리턴 한다.
public static boolean getDefaultLightWeightEnabled
lightWeightPopupEnabled 속성의 기본 값을 리턴 한다.
public boolean isPopupTrigger(MouseEvent e)
SDK 1.3이후, 발생한 마우스 이벤트가 현재 L&F에서 팝업 트리거인지 아닌지의 여부를 가리는 방법 중 하나이다.
public static void setDefaultLightWeightPopupEnabled(boolean aFlag)
lightWeightPopupEnabled 속성의 기본값을 설정한다. 이것은 팝업 메뉴를 위해 경량 혹은 중량 컴포넌트 사용 여부를 결정한다.
public void setSelected(Component c)
팝업 메뉴 모델에서 특정한 메뉴를 강제로 선택할 수 있다. 이것은 팝업 메뉴에서 단일 선택 모델의 이벤트를 변경시킨다.
public void updateUI( )
기본 사용자 인터페이스 매니저를 갱신하고 새로운 PopupMenuUI를 화면에 나타내기 위해 대리자(delegate)를 초기화 한다.

메뉴 요소 인터페이스
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 인터페이스를 상속한 것은 다음 챕터에서 다룰 예정이다.

팝업 메뉴 사용하기

다음 프로그램에는 JpopupMenu 클래스를 어떻게 사용하는지 보여주고 있다. [그림 14-9]와 같이 팝업 메뉴의 이벤트와 각각의 메뉴 아이템들 간의 통신을 하는 간단한 예제 이다.
//  PopupMenuExample.java
//
import java.awt.*;
import java.awt.event.*;
 
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
 
public class PopupMenuExample extends JPanel {
 
    public JPopupMenu popup;
 
    public PopupMenuExample(  ) {
        popup = new JPopupMenu(  ); 
        ActionListener menuListener = new ActionListener(  ) {
            public void actionPerformed(ActionEvent event) {
                System.out.println("Popup menu item [" +
                                   event.getActionCommand(  ) + "] was pressed.");
            }
        };
        JMenuItem item;
        popup.add(item = new JMenuItem("Left", new ImageIcon("left.gif")));
        item.setHorizontalTextPosition(JMenuItem.RIGHT);
        item.addActionListener(menuListener);
        popup.add(item = new JMenuItem("Center", new ImageIcon("center.gif")));
        item.setHorizontalTextPosition(JMenuItem.RIGHT);
        item.addActionListener(menuListener);
        popup.add(item = new JMenuItem("Right", new ImageIcon("right.gif")));
        item.setHorizontalTextPosition(JMenuItem.RIGHT);
        item.addActionListener(menuListener);
        popup.add(item = new JMenuItem("Full", new ImageIcon("full.gif")));
        item.setHorizontalTextPosition(JMenuItem.RIGHT);
        item.addActionListener(menuListener);
        popup.addSeparator(  );
        popup.add(item = new JMenuItem("Settings . . ."));
        item.addActionListener(menuListener);
 
        popup.setLabel("Justification");
        popup.setBorder(new BevelBorder(BevelBorder.RAISED));
        popup.addPopupMenuListener(new PopupPrintListener(  ));
 
        addMouseListener(new MousePopupListener(  ));
    }
 
    // 마우스 이벤트가 팝업 트리거인지 조사하는 내부(inner) 클래스
    class MousePopupListener extends MouseAdapter {
        public void mousePressed(MouseEvent e) { checkPopup(e); }
        public void mouseClicked(MouseEvent e) { checkPopup(e); }
        public void mouseReleased(MouseEvent e) { checkPopup(e); }
 
        private void checkPopup(MouseEvent e) {
            if (e.isPopupTrigger(  )) {
                popup.show(PopupMenuExample.this, e.getX(  ), e.getY(  ));
            }
        }
    }
 
    // 팝업 이벤트가 발생했을때 보여주는 내부(inner) 클래스 class PopupPrintListener implements PopupMenuListener {
        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
            System.out.println("Popup menu will be visible!");
        }
        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
            System.out.println("Popup menu will be invisible!");
        }
        public void popupMenuCanceled(PopupMenuEvent e) {
            System.out.println("Popup menu is hidden!");
        }
    }
 
    public static void main(String s[ ]) {
        JFrame frame = new JFrame("Popup Menu Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(new PopupMenuExample(  ));
        frame.setSize(300, 300);
        frame.setVisible(true);
    }
}
이 프로그램의 흥미로운 부분은 MousePopupListener의 메소드 사용일 것이다. 이것은 팝업 메뉴를 화면에 나타나게 하는 이벤트를 받았는지 보기위해 private 메소드 checkPopup( )를 호출한다. 유효한 트리거 이벤트를 발생시켰다면 적절한 위치에 팝업 메뉴가 보일 것이다. 이것은 앞서 보여준 "팝업 메뉴 나타내기"의 processMouseEvent( ) 오버라이딩 접근법 가운데 하나이다.

PopupMenuEvent 클래스

원하는 팝업 메뉴가 화면에 나타나거나, 사라질 때 혹은 취소될 때 리스너에게 전달하는 간단한 이벤트이다. 한가지 이벤트만 발생하는 것은 아니며 PopupMenuListener를 상속 받은 객체는 반드시 3개의 메소드를 작성해야 한다. 각각의 메소드는 정확히 원하는 팝업 메뉴 객체에 무슨 일이 발생했는지 나타낸다.

생성자
public PopupMenuEvent(Object source)
생성자는 이벤트를 발생시킨 객체의 레퍼런스를 가지고 있다.

PopupMenuListener 인터페이스

PopupMenuEvent 객체를 받기 위한 연결 고리 역할을 하는 PopupMenuListener 인터페이스는 세 개의 메소드를 포함하고 있다. 하나는 팝업 메뉴가 취소되었을 때 호출되며 나머지 두 개는 팝업 메뉴가 화면에 나타나거나 사라질 때 발생하는 메소드이다. 팝업 메뉴의 상태변화를 포착하기위한 리스너 객체는 반드시 이 인터페이스를 상속해야 한다.

메소드
public abstract void popupMenuCanceled(PopupMenuEvent e)
팝업 메뉴가 취소되었거나 화면에서 사라질 때 호출된다. (실제로는 드물게 발생한다)
public abstract void popupMenuWillBecomeInvisible(PopupMenuEvent e)
팝업 메뉴가 화면에서 사라지려고 할 때 발생한다.
public abstract void popupMenuWillBecomeVisible(PopupMenuEvent e)
팝업 메뉴가 화면에 보여지려고 할 때 호출된다. 이것은 현재 애플리케이션 상태에 따라 메뉴의 내용을 변경할 수 있는 아주 강력한 기능이다.

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