JLabel 스윙 컴포넌트를 상속받아 Custom 컴포넌트를 만들어 사용하고 싶습니

조회수 85회

안녕하세요 컴공 과정을 밟고 있는 학부생입니다. 다름이 아니라 제가 요즘 보드 게임 과제를 만들기 위해서 GUI를 공부하고 있는데요. 책을 봐도 구글링을 해도 문제의 원인의 감이 잡히지가 않습니다.

만드려는 보드 게임은 37개의 원 모양의 꼭짓점을 가지고 있고 게임 말은 이 꼭짓점에 위치하게 되고 이런 원 모양의 꼭짓점을 이벤트 처리도 받기 위해서 스윙 컴포넌트 JLabel을 상속받아서 만들기로 정하였습니다.

하지만 제가 원하는 대로 구현이 안되는 모습을 보이고 있습니다. 일단 테스트로 반지름이 17인 3개의 원을 각각 (0,0)과 (100,100), (200,200)에 띄우는 것을 목표로 테스트 해보았지만 아래의 이미지와 같이 (0,0)과 (200,200)에만 원이 보이고 나머지 1개는 보이지가 않습니다. 또 코드에서는 주석처리된 setLayout(null)을 주석해제하면 (0,0)에 위치한 원만 보이고 나머지는 보이지가 않습니다. 제가 알기로는 컨탠트 팬의 디폴트 배치관리자는 FlowLayout으로 알고 있고 이를 컴포넌트의 절대 위치를 사용하기 위해서 setLayout(null)을 사용한 것인데 이러한 결과가 나와서 의문입니다.

또 paint 메서드에서 문제가 발생한 건가 싶었지만 이 메서드는 단순히 컴포넌트를 생성할 때 JVM에게 의해서 호출되어 지정한 위치에 그림을 그려주는 역할로 이해를 하고 있어서 문제가 따로 없어보인다고 생각합니다. 제가 어딘가 빠트린 건지 잘못 이해를 하고 있는 건지.. 조언 부탁드립니다. 감사합니다!!

이미지

public class CircleFrame extends JFrame{    
    public CircleFrame() {
        Container c = getContentPane();
        //c.setLayout(null);

        BoardCircle c1 = new BoardCircle(0,0);
        c1.setLocation(c1.getCircleX(), c1.getCircleY());
        c1.setSize(34, 34);
        c.add(c1);

        BoardCircle c2 = new BoardCircle(100,100);
        c2.setLocation(c2.getCircleX(), c2.getCircleY());
        c2.setSize(34, 34);
        c.add(c2);

        BoardCircle c3 = new BoardCircle(200,200);
        c3.setLocation(c3.getCircleX(), c3.getCircleY());
        c3.setSize(34, 34);
        c.add(c3);

        setSize(500, 500);
        setVisible(true);
        setTitle("Circle Class Test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

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


class BoardCircle extends JLabel implements Serializable{
    int radius = 17;
    int x, y;

    BoardCircle( int x, int y){
        this.x = x;
        this.y = y;
        setSize(radius * 2, radius * 2);
        setVisible(true);
    }

    public int getCircleX() {
        return x;
    }

    public int getCircleY() {
        return y;
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g) ;
        g.setColor(Color.BLUE);
        g.fillOval(x, y, radius * 2, radius * 2);
    }
}

1 답변

  • import java.awt.*;
    import javax.swing.*;
    
    public class CircleFrame extends JFrame{    
        public CircleFrame() {
            Container c = getContentPane();
            c.setLayout(null);
    
            BoardCircle c1 = new BoardCircle(0,0);
            c.add(c1);
    
            BoardCircle c2 = new BoardCircle(100,100);
            c.add(c2);
    
            BoardCircle c3 = new BoardCircle(200,200);
            c.add(c3);
    
            setSize(500, 500);
            setVisible(true);
            setTitle("Circle Class Test");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
    
        public static void main(String[] args) {
            new CircleFrame();
        }
    }
    
    
    class BoardCircle extends JLabel{
        int radius = 17;
    
        BoardCircle(int x, int y){
            setLocation(x, y);
            setSize(radius * 2, radius * 2);
            setVisible(true);
        }
    
        @Override
        public void paint(Graphics g) {
            g.setColor(Color.BLUE);
            g.fillOval(0, 0, radius * 2, radius * 2);
        }
    }
    

    각 Component에서 paint 메소드로 얻을 수 있는 graphics context는 별도의 컨텍스트이며 컴포넌트 자신의 위치를 기준으로 위치를 잡는 것 같습니다. (스윙의 컴포넌트 구조를 잘 몰라서... 정확히는 모름.)

    위의 추측이 맞다는 가정하에,

    이미 setLocation()으로 컴포넌트의 위치를 잡았으므로 g.fillOval()에서 상대 위치를 고려한 값인 (0, 0)을 넣어야 합니다.

    • 뭐 다른 방법도 있는것 같은데 기존 코드를 최대한 건드리지 않는 방향으로 수정했습니다. digda 2019.6.12 21:29

답변을 하려면 로그인이 필요합니다.

Hashcode는 개발자들을 위한 무료 QnA 사이트입니다. 계정을 생성하셔야만 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)

ᕕ( ᐛ )ᕗ
로그인이 필요합니다

Hashcode는 개발자들을 위한 무료 QnA사이트 입니다. 계정을 생성하셔야만 글을 작성하실 수 있습니다.