자바 프로그래밍

자바 스윙 두번째 - 이미지를 가지는 JList 예제

plas 2020. 10. 16. 23:46

이번에는 아이콘을 이용해 리스트 관리하는 예제를 살펴본다. 상품 리스트처럼 이미지를 이용해 여러 개의 정보를 제공하는 경우가 많이 있다. 이것을 위해서 JList 클래스를 이용할 수 있다.

여기서는 스택오버플로우에 있는 예제를 이용하여 이미지를 이용하는 다음과 같은 예제를 살펴본다.

stackoverflow.com/questions/22266506/how-to-add-image-in-jlist

 

How to add image in jlist

Hi i have created a j list and there i want to add an image before any text in that text how can i do this i tried but i am not able to achieve my goal i want to add an image before list element"...

stackoverflow.com

프로그램 코드를 각자 실행해 보자.

MarioList.java
0.00MB

간단한 JList 사용법

먼저 간단한 리스트박스를 만드는 방법을 살펴보자. 스트링 배열을 이용해서 JList를 생성하고 그것을 패널에 추가하면 리스트가 보인다.

String[] listStr= { “우유”, “두부”, “소세지”, “생수” };
JList myList= new JList(listStr); 
myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

위와 같은 리스트박스에서 사용자가 어떤 것을 선택했을 때 이벤트 리스터가 불려진다. 이것을 처리하는 valueChanged 이벤트 핸들러를 만드는 방법은 다음과 같다. 먼저 선택한 것이 무엇인지 알기 위해 리스트에게 물어보는 방법이다. 이것을 이용하면 해당 데이터를 가져와 계산하거나 다른 컴포넌트의 값을 이것을 바탕으로 바꾸는 등의 동작을 할 수 있다. (예: 장바구니에 넣기)

  • int getSelectedIndex() : 선택한 항목 인덱스 값 반환
  • String getSelectedItem() : 선택한 항목의 이름 반환
  • Object getSelectedValue() : 선택된 항목(Object 타입) 반환
@Override
public void valueChanged(ListSelectionEvent e) {
   if (list.getSelectedIndex() == -1) { 
   } else { //선택되지 않은 경우 –1을 반환한다.
      //선택이 된 경우
   }

   if (list.getSelectedItem().equals(name) { 
      // 항목 이름이 name인 선택된 경우
   }
 
   if (list.getSelectedValue()!=null) { 
      //하나라도 선택된 경우
   }
}

리스트 모델 사용법

위의 방법은 리스트에 넣을 데이터가 변경되지 않을때 사용한다. 그러나 장바구니처럼 리스트에 아이템을 추가 또는 삭제하려면 위와 같은 배열로는 할 수 없다. 이것을 위해서는 DefaultListModel이라는 것을 직접 만들어주어야 한다. 모델은 리스트가 보여줄 데이터를 가지는데, 여기서 추가 또는 삭제하면 바로 리스트에 반영되므로 우리는 이 모델을 이용하여 추가 또는 삭제하면 된다. 모델을 먼저 만들어서 데이터를 다 넣고 그것으로 JList를 생성한다.

DefaultListModel model = new DefaultListModel();
model.addElement(“우유”);
model.addElement(“두부”);
model.addElement(“소세지”);
model.addElement(“생수”);

JList myList = new JList(model); 

모델에 데이터를 추가할 때는 addElement를 사용하면 되는데 이외에도 데이터를 추가 삭제하는 방법은 다음과 같다.

  • void add(int index, Object obj)
  • void addElement(Object obj)
  • Object remove(int index)
  • void removeAllElement()
  • boolean removeElement(Object obj)
  • void removeElementAt(int index)

이미지 리스트 사용법

요소가 스트링타입인 경우는 비교적 간단하게 처리할 수 있다. 이번에는 리스트 요소가 이미지를 가지는 경우를 살펴보자. 이미지와 함께 스트링을 가지도록 하고 싶다면 맵을 이용하여 데이터를 관리할 필요가 있다. 즉 맵이 데이터 모델의 역할을 한다. 

    private final Map<String, ImageIcon> imageMap;

    public MarioList() {
        String[] nameList = {"Mario", "Luigi", "Bowser", "Koopa", "Princess"};
        imageMap = createImageMap(nameList);
        JList list = new JList(nameList);
        list.setCellRenderer(new MarioListRenderer());

이미지를 가진 맵을 생성하는 방법은 다음과 같다. 여기서는 url을 이용하여 이미지 아이콘을 생성하고 그것을 맵에 추가했다.

    private Map<String, ImageIcon> createImageMap(String[] list) {
        Map<String, ImageIcon> map = new HashMap<>();
        try {
            map.put("Mario", new ImageIcon(new URL("http://i.stack.imgur.com/NCsHu.png")));
            map.put("Luigi", new ImageIcon(new URL("http://i.stack.imgur.com/UvHN4.png")));
            map.put("Bowser", new ImageIcon(new URL("http://i.stack.imgur.com/s89ON.png")));
            map.put("Koopa", new ImageIcon(new URL("http://i.stack.imgur.com/QEK2o.png")));
            map.put("Princess", new ImageIcon(new URL("http://i.stack.imgur.com/f4T4l.png")));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return map;
    }

그런데 이렇게 이미지 맵을 넣어주면 위에서 본 리스트모델 경우와는 달리 리스트가 알아서 그것을 화면에 보여주지 못한다. 대신 이 경우는 이미지를 화면에 어떻게 보여줄지 알려주는 렌더러를 우리가 제공해야 한다.

    public class MarioListRenderer extends DefaultListCellRenderer {
        Font font = new Font("helvitica", Font.BOLD, 24);
        @Override
        public Component getListCellRendererComponent(
                JList list, Object value, int index,
                boolean isSelected, boolean cellHasFocus) {

            JLabel label = (JLabel) super.getListCellRendererComponent(
                    list, value, index, isSelected, cellHasFocus);
            label.setIcon(imageMap.get((String) value));
            label.setHorizontalTextPosition(JLabel.RIGHT);
            label.setFont(font);
            return label;
        }
    }

렌더러는 각 요소를 위한 컴포넌트인 JLabel을 만들어주어야 한다. 이 라벨은 아이콘과 그 옆에 데이터를 스트링으로 보여주는 역할을 한다. (텍스트의 위치를 JLabel.RIGHT로 하면 오른쪽에 보이고 JLabel.SOUTH 하면 아래에 텍스트가 보이게 된다) 그러면 리스트는 이 라벨을 해당 인덱스에 추가해 준다. 이것은 매개변수가 많은 상당히 복잡한 함수다. 그러나 대부분의 일은 super에서 알아서 해 주고 우리는 아이콘을 설정하는 것과 라벨 내의 이미지와 텍스트의 위치, 폰트 등을 설정해 주면 된다.

이상과 같이 하면 이미지 리스트를 생성할 수 있다. 단, 이미지 리스트에 추가삭제도 되도록 하려면 리스트모델을 필요로 하는데, 그 경우는 코드가 좀더 복잡해 질 것이다.