JList 스트라이핑

Java SE 2006/12/24 11:12 Posted by Sun

글쓴이: Joshua Marinacci (NetBeans 엔지니어)

Swing에서 주목할 만한 것 중 하나는 사용자가 컴포넌트를 무엇이든 원하는 모습으로 커스터마이즈할 수 있다는 것이다. 이제는 표준 데스크탑 애플리케이션에 약간의 커스텀 룩을 추가하는 것은 상당히 흔한 일이 되어버렸다. 예를 들어, iTunes에서 Song List는 대체로 평범해 보이지만 인터페이스가 더 멋지게 보이도록 만드는 몇 가지 아주 미묘한 변화를 가지고 있다. 본 팁에서는 얼터네이팅 스트라이프(alternating stripe) 배경과 그레디언트 음영(gradient shaded) 선택을 통해 표준 Swing 리스트에 스타일을 가미하는 방법에 대해 알아보도록 한다.

JList 클래스는 JTable이나 JTree처럼 셀 렌더러를 이용하여 커스터마이즈할 수 있는데, 이는 본질적으로 리스트가 각 항목을 draw하기 위해 반복해서 호출하는 일종의 도장 툴(rubber stamp)로서 주로 운영체제에서 고유한 Look & Feel이 JLists를 각자의 native counterparts에 조화시키는데 사용된다. 한편, 사용자는 JList에 각자가 원하는 방식으로 스타일을 연출하기 위해 자체 셀 렌더러를 작성할 수도 있다. 이 경우 DefaultListCellRenderer 클래스를 서브클래스화하고 getListCellRendererComponent() 메소드를 오버라이드하기만 하면 된다.

리스트 셀을 스트라이핑하기 위해서는 반드시 한 줄씩 걸러 배경색을 바꾸어야 한다. 다음은 바로 그런 작업을 수행하는 간단한 셀 렌더러이다.


import java.awt.*; 
import javax.swing.*; 
 
class StripeRenderer extends DefaultListCellRenderer { 
    public Component getListCellRendererComponent(JList list, Object value, 
    int index, boolean isSelected, boolean cellHasFocus) { 
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, 
index, isSelected, cellHasFocus); 
       
if(index%2 == 0) { 
    label.setBackground(new Color(230,230,255)); 
} 
return label; 
    } 
} 


 

이 클래스는 단순히 getListCellRendererComponent() 메소드의 부모 버전을 호출한 다음, 인덱스가 짝수일 경우 배경색을 light blue로 설정하고 레이블을 리턴한다. index 값은 리스트 내 항목의 줄 번호를 나타낸다. JLabel에 대한 캐스트는 안전한데, 왜냐하면 이는 항상 JLabel 서브클래스를 리턴하도록 정해진 DefaultListCellRenderer의 서브클래스이기 때문이다.

사용자는 다음과 같이 이 클래스를 각자의 JList를 위한 렌더러로 설정할 수 있다.

위에 표시된 코드는 본 테크 팁의 텍스트 버전에서 갈무리할 수 있다.

그림 1은 완성된 렌더러를 보여준다.

Figure 1. JList with StripeRenderer
그림 1. StripeRenderer가 적용된 JList

사용자는 또한 선택한 리스트 셀을 위한 배경 그레디언트를 생성할 수도 있다. 이 때, 단순히 레이블의 배경색을 설정하는 것으로는 그레디언트를 생성할 수 없으므로, 반드시 사용자가 직접 리스트 셀 drawing을 구현해야 한다. DefaultListCellRenderer 클래스는 그 자체가 JLabel이며, 사용자가 getListCellRendererComponent()를 호출하면 몇 가지 셋업 작업을 수행한 후에 자신에게 레퍼런스를 리턴한다. 이는 사용자가 DefaultListCellRenderer를 서브클래스화하고 paintComponent(Graphics) 메소드를 오버라이드하여 drawing을 커스터마이즈할 수 있음을 의미한다. 코드의 형태는 다음과 유사하다.

class GradientSelectionRenderer extends DefaultListCellRenderer { 
    private boolean drawGradient = false; 
    public Component getListCellRendererComponent(JList list, Object value, 
    int index, boolean isSelected, boolean cellHasFocus) { 
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, 
index, isSelected, cellHasFocus); 
drawGradient = false; 
label.setOpaque(true); 
if(isSelected) { 
    drawGradient = true; 
    label.setForeground(Color.WHITE); 
    label.setBackground(Color.BLUE); 
    label.setOpaque(false); 
} 
return label; 
    } 
   
    protected void paintComponent(Graphics g) { 
if(drawGradient) { 
    Graphics2D gfx = (Graphics2D)g.create(); 
    GradientPaint gradient = new GradientPaint(0,0, Color.BLUE, 
    0,10,Color.BLACK); 
    gfx.setPaint(gradient); 
    gfx.fillRect(0,0,getWidth(),getHeight()); 
    gfx.dispose(); 
} 
super.paintComponent(g); 
    }   
} 
 

drawGradient 불리언(Boolean) 필드에 특히 유의할 것. 현재의 줄이 선택되면(getListCellRendererComponent()에 대한 isSelected 인수로 표시), drawGradient 불리언(Boolean)이 true로 설정되어 페인팅 코드는 그레디언트를 draw하는 것을 알게 된다. 그레디언트는 상단에서 하단까지 블루에서 블랙으로 draw하는 간단한 GradientPaint 오브젝트를 이용하여 생성된다. 이 때, label.setOpaque(false)에 대한 호출에 유의할 것. 이는 레이블에게 배경을 turn off하도록 지시하는데, 그렇지 않으면 일반 배경이 draw되어 커스텀 배경을 가리게 된다. 사용자가 이 크래스를 리스트 셀 렌더러로 설정하면 그림 2의 모습을 띠게 된다.

Figure 2. JList with GradientSelectionRenderer
그림 2. GradientSelectionRenderer가 적용된 JList

이 두 개의 렌더러도 그런대로 괜찮아 보이지만, 두 가지 효과를 동시에 낼 수 있다면 더 멋지지 않을까? 두 가지를 하나의 클래스에 결합할 수도 있지만, 더 쉬운 방법이 있다. 사용자는 현재의 항목이 선택된 다음 다른 항목을 위한 StripeRenderer를 리턴할 경우에만 StripeRenderer 클래스가 GradientSelectionRenderer의 인스턴스를 리턴하도록 만들 수 있다. 즉, GradientSelectionRendererStripeRenderer 내의 필드로 저장한 다음 현재의 항목이 선택될 때 이를 사용하면 되는 것이다.


class StripeRenderer extends DefaultListCellRenderer { 
    GradientSelectionRenderer gradient = new GradientSelectionRenderer(); 
    public Component getListCellRendererComponent(JList list, Object value, 
    int index, boolean isSelected, boolean cellHasFocus) { 
if(isSelected) { 
    return gradient.getListCellRendererComponent(list, value, 
    index, isSelected, cellHasFocus); 
} 
// else, do the usual stripe renderer stuff 
 ... 
    } 
} 
... 
list.setCellRenderer(new StripeRenderer()); 

Figure 3. JList with GradientSelectionRenderer
그림 3. GradientSelectionRenderer가 적용된 JList

이것으로 작업이 완료되었고, 이제 두 개의 렌더러가 하나로 결합되었다. 셀 렌더러는 커다란 변화 없이 통상적인 애플리케이션에 운치를 더해주는 훌륭한 수단으로, 프로그램을 돋보이게 하는 효과가 매우 뛰어나다. 리스트와 리스트 셀 렌더러에 관한 자세한 내용은 다음 문서를 참조하기 바란다.

"Java SE" 카테고리의 다른 글

2006/12/24 11:12 2006/12/24 11:12

TRACKBACK :: http://blog.sdnkorea.com/blog/trackback/151

댓글을 달아 주세요

  1. 박정숙  수정/삭제  댓글쓰기

    좋은 정보 감사해요~

    2007/09/19 04:02
  2. 박정숙  수정/삭제  댓글쓰기

    좋은 정보 감사해요~

    2007/09/19 04:02
  3. 고진구  수정/삭제  댓글쓰기

    아~~ 자바의 무한함이여.

    2007/09/19 16:10
  4. 김복선  수정/삭제  댓글쓰기

    좋은 정보 많이 얻고 갑니다.

    2007/09/19 22:50
[로그인][오픈아이디란?]

◀ Prev 1  ... 316 317 318 319 320 321 322 323 324  ... 626  Next ▶