Thread로 구현한 썸네일 Gallery 뷰어

heeezni·2025년 6월 6일

Java GUI 프로젝트

목록 보기
12/20
post-thumbnail

히트박스

화면에 보이는 요소(이미지, 오브젝트 등)에 대해
실제로 클릭되거나 충돌이 감지되는 논리적인 사각형 영역

➡️ 갤러리 예제에서의 적용
이미지를 패널에 직접 그리고, g.drawImage(...)
그 위치와 크기 정보를 Rectangle[]으로 저장해 new Rectangle(...)
클릭 이벤트 충돌 판정용으로 사용하는 구조 rect.contains(...)

보이는 건 이미지,
감지되는 건 히트박스(Rectangle)인 구조


구성 요소역할
p_west (JPanel)썸네일 이미지들을 drawImage()로 직접 그리는 영역
rects[i] (Rectangle)눈에는 보이지 않지만, 해당 썸네일 영역의 위치와 크기를 기억하고 있음
MouseListener마우스 클릭 시 e.getPoint()rects[i] 중 어디에 속하는지 판단 (rect.contains(...))

public class Gallery extends JFrame {
    JPanel p_west;      // 좌측 썸네일들이 그려질 패널
    JPanel container;   // 북쪽, 중앙 패널들을 감쌀 컨테이너 (BorderLayout 사용)
    JPanel p_north;     // 북쪽 컨트롤러 영역 (현재 비어 있음)
    JPanel p_center;    // 선택한 큰 이미지가 표시될 패널

    ImageUtil imageUtil = new ImageUtil();       // 이미지 로딩 유틸리티
    Image[] images = new Image[9];               // 총 9장의 이미지 배열

    // 썸네일 위치 정보를 담을 사각형 배열 (이벤트 판별용)
    Rectangle[] rects = new Rectangle[images.length];

    float y = 10f;       // 현재 빨간 사각형 y 좌표
    float a = 0.1f;      // 감속도 비율 계수
    int targetY;         // 빨간 사각형이 도달해야 할 목표 y 좌표
    int currentIndex;    // 현재 선택된 이미지의 인덱스
    Thread thread;       // 애니메이션용 스레드 (게임루프 역할)

    public Gallery() {

        createImage(); // 이미지 및 rect 좌표 초기화

        // 애니메이션용 스레드 (10ms 간격으로 repaint + 이동)
        thread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(10); // 주기적 호출
                        move();           // y값 업데이트 (감속도 이동)
                        p_west.repaint(); // 썸네일 패널 다시 그리기
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }
                }
            }
        };
        thread.start();

        // 썸네일 패널 구현 (커스텀 paintComponent)
        p_west = new JPanel() {
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);

                // 썸네일 9장 그리기
                for (int i = 0; i < images.length; i++) {
                    g.drawImage(images[i], 5, 10 + (95 * i), 90, 90, this);
                }

                // 빨간 사각형 포인터 그리기
                Graphics2D g2 = (Graphics2D) g;
                g2.setStroke(new BasicStroke(5));
                g.setColor(Color.RED);
                g.drawRect(5, (int) y, 90, 90);
            }
        };

        container = new JPanel();
        p_north = new JPanel();

        // 큰 이미지 보여줄 중앙 패널 구현
        p_center = new JPanel() {
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.drawImage(images[currentIndex], 0, 0, 800, 850, this);
            }
        };

        // 스타일
        p_west.setBorder(new LineBorder(Color.LIGHT_GRAY));
        p_west.setPreferredSize(new Dimension(100, 800));

        // 조립
        add(p_west, BorderLayout.WEST);
        container.setLayout(new BorderLayout());
        container.add(p_north, BorderLayout.NORTH);
        container.add(p_center);
        add(container);

        // 썸네일 클릭 시 이벤트 처리
        p_west.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                for (int i = 0; i < rects.length; i++) {
                
                	//✅rect.contains(click)
                    if (rects[i].contains(e.getPoint())) { 
                        currentIndex = i;       // 현재 선택 이미지 설정
                        p_center.repaint();     // 큰 이미지 갱신
                        targetY = rects[i].y;   // 이동할 목표 y좌표 설정
                    }
                }
            }
        });

        targetY = 10; // 초기 포인터 위치

        setSize(900, 900);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    // 이미지 객체 생성 및 썸네일 좌표 rect 배열 초기화
    public void createImage() {
        for (int i = 0; i < images.length; i++) {
            images[i] = imageUtil.getImage("geographic/animal" + (i + 1) + ".jpg", 90, 90);
            rects[i] = new Rectangle(5, 10 + (95 * i), 90, 90);
        }
    }

    // 감속도 공식 적용
    public void move() {
        y = y + a * (targetY - y);
    }

    public static void main(String[] args) {
        new Gallery();
    }
}

rect.contains(click)

사용자가 클릭한 좌표가 이 사각형 안에 들어 있나요?

if (rects[i].contains(e.getPoint())) {
    currentIndex = i;         // 선택한 이미지 인덱스 저장
    targetY = rects[i].y;     // 빨간 사각형의 목표 y좌표 설정
    p_center.repaint();       // 오른쪽 큰 이미지 갱신
}
  • rects[i]는 썸네일 하나의 위치 사각형
  • e.getPoint()는 사용자가 클릭한 위치 (마우스 좌표)

사용자가 클릭한 위치가 해당 썸네일 사각형 안에 있으면 → 클릭 처리

profile
아이들의 가능성을 믿었던 마음 그대로, 이제는 나의 가능성을 믿고 나아가는 중입니다.🌱

0개의 댓글