티스토리 뷰

PL/JAVA

[Java] 자바 - 그래픽

poopooreum 2024. 6. 14. 12:49
반응형

✏️ 스윙 컴포넌트 그리기

paintComponent()

모든 스윙 컴포넌트가 가지고 있는 메소드로서, 스윙 컴포넌트가 자신의 내부를 그리며 원형은 아래와 같다.

void paintComponent(Graphics g) // 컴포넌트 내부 모양 그리기

 

또한 paintComponent()JComponent의 추상 메소드이므로 모든 스윙 컴포넌트가 오버라이딩하여 가지고 있다. 그리고 스윙 컴포넌트에 paintComponent()가 호출되는 경우는 아래와 같다.

// 컴포넌트의 크기나 위치 변경 등 컴포넌트에 변화가 생길 때
// 다른 윈도우에 의해 가려졌다가 드러날 때
// 아이콘화되었다가 본래 크기로 복구할 때
// 응용프로그램이 컴포넌트의 repaint() 메소드를 호출하여 강제로 다시 그릴 때

 

JPanel 상속받아서 도형 그리기

JPanel은 빈 캔버스와 같이 아무 모양도 없는 빈 컨테이너로, 다양한 GUI를 창출할 수 있는 캔버스로 적합하여 그래픽을 위해 많이 사용한다. 그래서 JPanel을 상속받은 후 paintComponent()를 오버라이딩하여 사용한다.

package ex;
import java.awt.*;
import javax.swing.*;
public class paintJPanelEx extends JFrame{
    private MyPanel panel = new MyPanel();
    public paintJPanelEx() {
        setTitle("JPanel 상속받기");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(panel); // 생성한 panel을 컨텐트팬으로 사용

        setSize(250,220);
        setVisible(true);
    }

    // JPanel을 상속받는 새 패널 구현
    class MyPanel extends JPanel {
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.BLUE);
            g.drawRect(10,10,50,50);
            g.drawRect(50,50,50,50);

            g.setColor(Color.RED);
            g.drawRect(90,90,50,50);
        }
    }

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

 

 

✏️ Graphics

그래픽 기반 GUI 프로그래밍

그래픽 기반 GUI 프로그래밍은 스윙 컴포넌트를 사용하지 않고 선, 원, 이미지 등을 직접 그려 GUI 화면을 구성하는 방식으로 장점은 아래와 같다.

  1. 스윙 컴포넌트로 만들 수 없는 모양을 자유자재로 만들어 낼 수 있다.
  2. 컴포넌트 그리기보다 그려지는 속도가 빨라서 화면이 역동적으로 변하고 속도가 중요한 곳에서 사용 가능하다.
  3. 스윙도 결국 하부에는 그래픽을 기반으로 작성되어서, 자바의 GUI 바탕 기술을 이해하는데 도움이 된다.
  4. 개발자는 그래픽을 이용하여 자신만의 컴포넌트를 창작할 수 있다.

Graphics

Graphics 클래스의 경로명은 java.awt.Graphics이며 그리기, 칠하기, 이미지 출력, 클리핑 등 다양한 필드와 메소드를 제공한다. 자바 그래픽의 좌표 체계는 왼쪽 상단 모서리가 (0,0)이고, 오른쪽으로 x축값이 증가하고 아래쪽으로 y축값이 증가한다. 그리고 Graphics가 제공하는 기능은 아래와 같다.

  • 색상 선택하기
  • 문자열 그리기
  • 도형 그리기
  • 도형 칠하기
  • 이미지 그리기
  • 클리핑

 

문자열 그리기

void drawString(String str, int x, int y)
// str 문자열을 (x,y)영역에 그린다
// (30,30)과 (60,60) 좌표에 JPanel을 상속받아서 문자열 그리기
package ex;
import javax.swing.*;
import java.awt.*;
public class GraphicsDrawStringEx extends JFrame{
    private MyPanel panel = new MyPanel();
    public GraphicsDrawStringEx() {
        setTitle("문자열 그리기 예제");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(panel);
        setSize(250,200);
        setVisible(true);
    }

    class MyPanel extends JPanel{
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawString("자바는 재밌다~",30,30);
            g.drawString("많이 많이 재밌다",60,60);
        }
    }

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

 

 

Color 클래스

Color(int r, int g, int b) // r, g, b 값으로 sRGP 색 생성
Color(int rgb) // rgp는 32비트의 정수지만 하위 24비트만 유호, 0X00rrggbb로 표현

 

Font 클래스

Font(String fontFace, int style, int size)
// fontFace는 폰트의 이름("고딕체", "맑은 돋음" 등등)
// style은 문자의 스타일로 Font.BOLD, Font.ITALIC, Font.PLAIN 중 택일
// size는 픽셀 단위의 문자 크기

 

Graphic에서의 색상과 폰트 활용

void setColor(Color color) // 그래픽 색을 지정 후, 그리기 시에 색으로 사용
void setFont(Font font) // 그래픽 폰트를 font로 지정, 문자열 출력 시 폰트로 사용

 

Color와 Font를 이용하여 문자열 그리기

// "How much?"는 Arial체로 "This much!"는 Jokerman체를 사용하여 출력하고 10픽셀에서 50픽셀까지 증가시키면서 출력
package ex;
import javax.swing.*;
import java.awt.*;
public class GraphicColorFontEx extends JFrame{
    private MyPanel panel = new MyPanel();
    public GraphicColorFontEx() {
        setTitle("Color, Font 사용 예제");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(panel);
        setSize(350,470);
        setVisible(true);
    }

    class MyPanel extends JPanel {
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.BLUE);
            g.drawString("I LOVE JAVA",30,30);
            g.setColor(Color.RED);
            g.setFont(new Font("Arial",Font.ITALIC,30));
            g.drawString("How Much?",30,60);
            g.setColor(new Color(0x00ff00ff));
            for(int i=1;i<=5;i++){
                g.setFont(new Font("Jokerman", Font.ITALIC,i*10));
                g.drawString("This much!",30,60+i*60);
            }
        }
    }

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

 

 

✏️ 도형 그리기와 칠하기

도형 그리기

// (x1, y1)에서 (x2,y2)까지 선을 그림
void drawLine(int x1, int y1, int x2, int y2) 

// (x,y)에서 w x h 크기의 사각형에 내접하는 원을 그린다
void drawOval(int x, int y, int w, int h)

// (x,y)에서 w x h 크기의 사각형을 그린다
void drawRect(int x, int y, int x, int h)

// (x,y)에서 w x h 크기의 사각형을 그리되, 4개의 모서리는 arcWidth와 arcHeight를 이용하여 원호로 그린다
void drawRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight)
// 컨텐트팬에 (20,20)부터 (100,100)까지 빨간 선 그리기
package ex;
import javax.swing.*;
import java.awt.*;
public class GraphicDrawLineEx extends JFrame{
    private MyPanel panel = new MyPanel();
    public GraphicDrawLineEx() {
        setTitle("drawLine 예제");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(panel);

        setSize(200,170);
        setVisible(true);
    }

    class MyPanel extends JPanel{
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.RED);
            g.drawLine(20,20,100,100);
        }
    }

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

 

원호와 페다각형 그리기

// (x,y)에서 w x h 크기의 사각형에 내접하는 원호를 그린다. 3시 방향이 0도 기점이며
// startAngle 지점에서 arcAngle 각도만큼 원호를 그리며 arcAngle 값이 양수이면 반시계, 음수이면 시계 방향이다
void drawArc(int x, int y, int w, int h, int startAngle, int arcAngle)

// x, y 배열에 저장된 점들 중 n개를 연결하는 폐다각형을 그린다.
void drawPolygon(int []x, int []y, int n)

 

도형 칠하기

// 도형 칠하기는 도형의 외곽선과 내부를 동일한 색으로 칠하는 기능으로 draw메소드를 fill로 바꿔주면 된다.
// 다만 도형의 외곽선과 내부를 분리하여 칠하는 기능이 없으므로 내부 색과 외곽선 색을 달리하고자 하면
// 도형 내부를 칠한 후, 다른 색으로 외곽선을 그려야 한다.
drawRect() => fillRect()
drawArc() => fillArc()
// fill() 메소드로 다양한 도형 그리기
package ex;
import javax.swing.*;
import java.awt.*;
public class GraphicsFillEx extends JFrame{
    private MyPanel panel = new MyPanel();
    public GraphicsFillEx() {
        setTitle("Fill 채우기 예제");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(panel);

        setSize(100,350);
        setVisible(true);
    }

    class MyPanel extends JPanel{
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.RED);
            g.fillRect(10,10,50,50);
            g.setColor(Color.BLUE);
            g.fillOval(10,70,50,50);
            g.setColor(Color.GREEN);
            g.fillRoundRect(10,130,50,50,20,20);
            g.setColor(Color.MAGENTA);
            g.fillArc(10,190,50,50,20,270);
            g.setColor(Color.ORANGE);
            int[] x = {30, 10, 30, 60};
            int[] y = {250, 275, 300, 275};
            g.fillPolygon(x,y,4);
        }
    }

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

 

 

✏️ 이미지 그리기

스윙에서 이미지는 다음과 같은 2가지 방법을 사용한다.

  • JLabel 컴포넌트를 이용하여 이미지 그리기
  • Graphics의 메소드를 이용하여 이미지 그리기

첫 번째 방법은 이전의 게시물에서 다루었던 방법이다. => 클릭

두 번재 방법은 Graphics의 drawImage() 메소드를 호출하여 원하는 위치에, 원하는 크기로, 원하는 비율로 이미지를 출력하는 방법이다. 여기서는 두 번째 방법을 다루고자 한다.

 

Graphics로 이미지 그리기

// 원본크기로 그리기, img를 그래픽 영역의 (x,y) 위치에 img의 원본 크기로 그린다
// bgColor는 이미지의 투명한 부분에 칠해지는 색깔
// observer는 이미지 그리기의 완료를 통보받는 객체
boolean drawImage(Image img, int x, int y, Color bgColor, ImageObserver observer) 
boolean drawImage(Image img, int x, int y, ImageObserver observer)
// 크기 조절하여 그리기
// img를 그래픽 영역의 (x,y)위치에 width x height 크기로 조절하여 그린다
boolean drawImage(Image img, int x, int y, int width, int height, Color bgColor, ImageObserver observer)
boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)
// 원본의 일부분을 크기 조절하여 그리기
// img의 (sx1,sy1) 에서 (sx2,sy2)로 구성된 사각형 부분을 그리팩 영역 내의 (dx1,dy1)에서 (dx2,dy2)의 사각형 크기로 변형하여 그린다.
boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgColor, ImageObserver observer)
boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)

 

(20,20)에 이미지 원본 크기로 그리기

 

package ex;
import javax.swing.*;
import java.awt.*;
public class GraphicsDrawImageEx extends JFrame{
    private MyPanel panel = new MyPanel();
    public GraphicsDrawImageEx() {
        setTitle("원본 크기로 이미지 그리기");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(panel);

        setSize(300,420);
        setVisible(true);
    }

    class MyPanel extends JPanel{
        private ImageIcon icon = new ImageIcon("images/인스타.jpg");
        private Image img = icon.getImage();
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(img,20,20,this);
        }
    }

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

 

JPanel로 만든 패널에 꽉 차도록 이미지 그리기

package ex;
import javax.swing.*;
import java.awt.*;
public class GraphicDrawImageEx2 extends JFrame{
    private MyPanel panel = new MyPanel();
    public GraphicDrawImageEx2() {
        setTitle("패널의 크기에 맞추어 이미지 그리기");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(panel);

        setSize(200,300);
        setVisible(true);
    }

    class MyPanel extends JPanel{
        private ImageIcon icon = new ImageIcon("images/인스타.jpg");
        private Image img = icon.getImage();
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(img, 0, 0, getWidth(),getHeight(), this);
        }
    }

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

 

이미지의 일부분을 크기 조절하여 그리기

package ex;
import javax.swing.*;
import java.awt.*;
public class GraphicDrawImageEx3 extends JFrame{
    private MyPanel panel = new MyPanel();
    public GraphicDrawImageEx3() {
        setTitle("이미지의 일부분을 크기 조절하기");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(panel);

        setSize(300,300);
        setVisible(true);
    }

    class MyPanel extends JPanel{
        private ImageIcon icon = new ImageIcon("images/자바.jpg");
        private Image img = icon.getImage();
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(img,20,20,250,100,100,50,200,200,this);
        }
    }

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

 

 

✏️ 클리핑

클리핑 개요

클리핑이란 컴포넌트의 전체 그래픽 영역 내 특정 사각형 영역에만 그래픽이 이루어지도록 하는 기능이다. 클리핑이 이루어지는 사각형 영역을 클리핑 영역이라고 부르며 반드시 사각형으로 설정된다.

 

클리핑 영역 설정 메소드

Graphics 객체에는 클리핑 영역 정보를 나타내는 프로퍼티와 클리핑 영역을 다루는 메소드를 가지고 있다. 개발자는 아래와 같은 메소드를 통해 클리핑 영역을 수정할 수 있으며 도형 그리기, 칠하기, 문자열 출력, 이미지 그리기 등이 실행되면 클리핑 영역에만 그래픽이 이루어진다. paintComponent(Graphics g)가 다시 호출될 때, 이전에 설정한 클리핑 영역 정보가 g에 저장되지 않는다.

// 그래픽 대상 컴포넌트의 (x,y) 위치에서 w x h의 사각형 영역을 클리피 영역으로 설정
void setClip(int x, int y, int w, int h)

// Graphics 객체 내에 유지되어 온 기존 클리핑 영역과 (x,y)에서 w x h 크기로 지정된 사각형 영역의
// 교집합 영역을 새로운 클리핑 영역으로 설정한다. cliRect()가 계속 호출되면 클리핑 영역이 줄어든다.
void clipRect(int x, int y, int w, int h)

 

클리핑 영역 그리기

package ex;
import javax.swing.*;
import java.awt.*;
public class GraphicsClipEx extends JFrame{
    private MyPanel panel = new MyPanel();
    public GraphicsClipEx() {
        setTitle("클리핑 예제");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(panel);

        setSize(300,400);
        setVisible(true);
    }

    class MyPanel extends JPanel{

        private ImageIcon icon = new ImageIcon("images/티스토리.jpg");
        private Image img = icon.getImage();

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setClip(100,20,50,150);
            g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
            g.setColor(Color.YELLOW);
            g.setFont(new Font("Arial", Font.ITALIC,40));
            g.drawString("Go Gator",10,150);
        }
    }

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

 

 

✏️ 스윙의 페인팅 메커니즘

스윙의 페인팅과 관련된 JComponent의 메소드

void print(Graphics g) // 컴포넌트 자신과 모든 자손 그리기
void paintComponent(Graphics g) // 컴포넌트 자신의 내부 모양 그리기
void paintBorder(Graphics g) // 컴포넌트의 외곽 그리기
void paintChildren(Graphics g) // 컴포넌트의 자식들 그리기(컨테이너의 경우)

 

스윙에서 컨테이너와 컴포넌트가 그려지는 과정(예시)

컨테이너의 paint() 메소드는 먼저 자신의 paintComponent(g)를 호출하여 자신의 내부를 그린다. 그런 다음 paintBorder(g)를 호출하여 자신의 영역 외곽을 그린다. 마지막으로 자식들을 그리기 위해 paintChildren(g)를 호출한다. paintChildren(g) 메소드의 코드는 모든 자식들에 대해 하나씩 순서대로 paint(g) 메소드를 호출하도록 작성되어 있다. 이런 식으로 마지막 자식 컴포넌트까지 그려지면 페인팅이 종료된다. JButton처럼 순수 컴포넌트의 경우 자식이 없으므로 paintChilder(g)은 호출되지 않는다. 아래 사진은 방금전 말을 그림으로 설명해 놓은 것이다.

public void paint(Graphics g){ //g가 아래 3개의 메소드에 그대로 전달
	...
    paintComponent(g); // 1. 컴포넌트 자신의 내부 모양 그리기
    paintBorder(g); // 2. 컴포넌트 자신의 외곽 그리기
    paintChildred(g); // 3. 컴포넌트의 자식들 그리기
}

스윙의 컴포넌트 페인팅 과정

 

repaint()

프로그램에서 컴포넌트의 모양, 텍스트 크기, 색 등을 변경하는 경우, 이 변화들이 스크린이 바로 나타나지 않는 경우들이 있다. 이 변화가 스크린에 반영되기 위해서는 컴포넌트의 paintComponent()가 실행되어야 하는데 paintComponent()를 직접 호출해서는 안 된다. 왜냐하면 이 메소드는 페인팅 과정에서 자바 플랫폼에 의해 호출되어야 하기 때문이다. 이럴 때 사용할 수 있는 메소드가 repaint()이다.

component.repaint(); // 컴포넌트 다시 그리기 지시


reapint()는 Component 클래스의 메소드로 자바 플랫폼에게 컴포넌트의 변화를 알려주고 강제로 페인팅할 것을 지시한다. 그리고 컴포넌트를 다시 그리기 위해서는 부모 컴포넌트부터 그리는 것이 좋다. 컴포넌트의 크기나 위치가 변경되었다면, 컴포넌트의 부모에게 컴포넌트의 이전 모양이나 이전 위치의 잔상을 지우도록 해야 하기 때문이다.

component.getParent().repaint(); // 컴포넌트의 부모 컨테이너에게 다시 그리기 지시

 

revalidate()

revalidate()는 컨테이너의 배치관리자에게 자식 컴포넌트의 배치를 다시 하도록 지시하는 메소드이다. 컨테이너에 컴포넌트를 새로 삽입하거나 삭제하여 컨테이너가 출력된 모양에 변화가 생겼다면 revalidate()를 호출하여 컨테이너를 다시 그리도록 해야 한다. revalidate()가  내부적으로 repaint()를 부르지만 상황에 따라 잘 처리되지 않을 수도 있으므로 아래의 두 라인을 모두 호출해야 한다.

container.revalidate(); // 컨테이너에 부착된 컴포넌트의 재배치 지시
container.repaint(); // 컨테이너 다시 그리기 지시

 

마우스를 이용하여 선 그리기

package ex;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class GraphicsDrawLineMouseEx extends JFrame{
    private MyPanel panel = new MyPanel();
    public GraphicsDrawLineMouseEx() {
        setTitle("drawing Line By Mouse");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setContentPane(panel);

        setSize(300,300);
        setVisible(true);
    }

    public static void main(String[] args) {
        new GraphicsDrawLineMouseEx();
    }
    class MyPanel extends JPanel{
        private Vector<Point> vStart = new Vector<>(); // 시작점
        private Vector<Point> vEnd = new Vector<>(); // 끝점
        public MyPanel(){
            addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    Point startP = e.getPoint();
                    vStart.add(startP);
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    Point endP = e.getPoint();
                    vEnd.add(endP);

                    repaint();
                }
            });
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.BLUE);

            for(int i=0;i< vStart.size();i++){
                Point s = vStart.elementAt(i);
                Point e = vEnd.elementAt(i);

                g.drawLine((int)s.getX(), (int)s.getY(),(int)e.getX(),(int)e.getY());
            }
        }
    }
}

 

JButton을 상속받아 새로운 버튼 생성

package ex;
import javax.swing.*;
import java.awt.*;
public class paintComponentEx extends JFrame {
    public paintComponentEx() {
        setTitle("새로운 버튼만들기");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Container c = getContentPane();
        c.setLayout(new FlowLayout());
        MyButton b = new MyButton("New Button");
        b.setOpaque(true);
        b.setBackground(Color.CYAN);
        c.add(b);
        setSize(250,200);
        setVisible(true);
    }

    class MyButton extends JButton{
        public MyButton(String s){
            super(s);
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            g.setColor(Color.RED);
            g.drawOval(0,0,this.getWidth()-1,this.getHeight()-1);
        }
    }

    public static void main(String[] args) {
        new paintComponentEx();
    }
}
반응형

'PL > JAVA' 카테고리의 다른 글

[JAVA] 자바 - 고급 스윙 컴포넌트  (0) 2024.06.16
[JAVA] 자바 - 스레드와 멀티태스킹  (0) 2024.06.15
[JAVA] 자바 - 스윙 컴포넌트  (2) 2024.06.13
[JAVA] 자바 - 이벤트  (0) 2024.06.12
[JAVA] 자바 - GUI 기초(AWT와 스윙)  (2) 2024.06.11
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함