14. 2D 그래픽스
UI 프로그램에서 윈도우, 버튼, 이미지 등은 모두 화면에 그려진 2D 그래픽입니다. Swing은 개발자가 직접 2D 그래픽을 그릴 수 있도록 Java2D API를 제공합니다.
1. Canvas와 Graphics
그림을 그리기 위해서는 도화지(Canvas)와 붓(Graphics)이 필요합니다.
- Canvas: 그림이 그려지는 컴포넌트 (도화지)
- Graphics: 그림을 그리는 도구 (붓)
그리기 매커니즘
Canvas는 화면에 보일 준비가 되면 paint(Graphics g) 메서드를 호출하여 그림을 그립니다.
sequenceDiagram
participant System
participant Canvas
participant Graphics
System->>Canvas: 드로잉 요청 (최초, 크기변경 등)
Canvas->>Canvas: paint(Graphics g) 호출
Canvas->>Graphics: 그림 그리기 메서드 호출
Graphics-->>Canvas: 화면에 출력
paint() 메서드가 호출되는 시점
- 윈도우가 처음 나타날 때
- 윈도우 크기가 변경될 때
- 윈도우가 다른 창에 가려졌다가 다시 나타날 때
- 프로그램에서 강제로
repaint()를 호출할 때
예제 (CanvasPaintExample)
package sec14.exam01_paint;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class CanvasPaintExample extends JFrame {
public CanvasPaintExample() {
setTitle("paint() 메서드 호출 시점");
getContentPane().add(new MyCanvas(), BorderLayout.CENTER);
setSize(300, 200);
}
// 사용자 정의 Canvas
class MyCanvas extends Canvas {
@Override
public void paint(Graphics g) {
g.drawString("윈도우 크기를 변경해보세요", 50, 80);
System.out.println("paint() 메서드 실행");
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new CanvasPaintExample().setVisible(true);
});
}
}
2. 다시 그리기 (Repaint)
개발자가 직접 paint()를 호출할 수는 없습니다. 대신 repaint()를 호출하면 시스템이 update()를 거쳐 paint()를 호출합니다.
Repaint 흐름
repaint()호출update(Graphics g)호출: 기본적으로 화면을 지움 (배경색으로 채움)paint(Graphics g)호출: 다시 그림
화면이 깜빡거리는 것을 방지하거나, 이전 그림을 유지하려면 update() 메서드를 재정의하여 super.update(g)(화면 지우기)를 호출하지 않도록 해야 합니다.
@Override
public void update(Graphics g) {
paint(g); // 화면을 지우지 않고 바로 그리기
}
예제: 마우스 드래그로 그림 그리기 (RepaintExample)
package sec14.exam02_repaint;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class RepaintExample extends JFrame {
public RepaintExample() {
setTitle("재 드로잉");
getContentPane().add(new MyCanvas(), BorderLayout.CENTER);
setSize(500, 400);
}
class MyCanvas extends Canvas implements MouseMotionListener {
private int x, y;
public MyCanvas() {
addMouseMotionListener(this);
}
@Override
public void update(Graphics g) {
paint(g); // 화면 지우기 생략
}
@Override
public void paint(Graphics g) {
g.drawString("*", x, y);
}
@Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint(); // 다시 그리기 요청
}
@Override
public void mouseMoved(MouseEvent e) {}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new RepaintExample().setVisible(true));
}
}
3. 그래픽 주요 메서드
Graphics 객체는 다양한 그리기 메서드를 제공합니다.
색상 및 폰트 설정
| 메서드 | 설명 |
| :—————— | :—————————————————– |
| setColor(Color c) | 붓의 색상 설정 (예: Color.RED, new Color(r, g, b)) |
| setFont(Font f) | 글자 폰트 설정 |
Font 생성: new Font("글꼴이름", 스타일, 크기)
- 스타일:
Font.PLAIN,Font.BOLD,Font.ITALIC(조합 가능:Font.BOLD | Font.ITALIC)
도형 그리기 메서드
| 종류 | 외곽선 그리기 (draw...) | 내부 채우기 (fill...) | 설명 |
| :————– | :————————- | :———————- | :———————————- |
| 선 | drawLine(x1, y1, x2, y2) | - | (x1, y1)에서 (x2, y2)까지 선 그리기 |
| 사각형 | drawRect(x, y, w, h) | fillRect(x, y, w, h) | (x, y) 위치에 w x h 크기 사각형 |
| 원/타원 | drawOval(x, y, w, h) | fillOval(x, y, w, h) | 사각형 안에 내접하는 원/타원 |
| 둥근 사각형 | drawRoundRect(...) | fillRoundRect(...) | 모서리가 둥근 사각형 |
| 입체 사각형 | draw3DRect(...) | fill3DRect(...) | 음영 효과가 있는 사각형 |
| 호 (부채꼴) | drawArc(...) | fillArc(...) | 원의 일부분 |
| 다각형 | drawPolygon(...) | fillPolygon(...) | 점들의 배열을 이어 만든 다각형 |
예제 (ShapeExample)
// paint 내부
g.drawOval(50, 50, 50, 50); // 원
g.setColor(Color.RED);
g.drawLine(50, 100, 100, 150); // 선
g.setColor(Color.BLUE);
g.drawRoundRect(200, 50, 120, 80, 30, 30); // 둥근 사각형
4. 안티 알리아싱 (Anti-aliasing)
거친 계단 현상(Aliasing)을 없애고 부드럽게 그리는 기능입니다. Graphics2D로 캐스팅하여 설정합니다.
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
// 그리기 코드...
}
5. 이미지 그리기
이미지 파일을 로딩하여 화면에 그립니다.
이미지 로딩 방법
- Toolkit 이용:
Image img = Toolkit.getDefaultToolkit().getImage("경로/파일명"); - ImageIcon 이용:
Image img = new ImageIcon("경로/파일명").getImage(); - 리소스 경로 (classpath):
URL url = getClass().getResource("파일명"); Image img = Toolkit.getDefaultToolkit().getImage(url);
이미지 그리기
// g.drawImage(Image img, int x, int y, ImageObserver observer)
g.drawImage(img, 0, 0, this);
6. JPanel 배경 이미지 넣기
JPanel은 컨테이너이므로 자식 컴포넌트들 뒤에 배경을 그려야 합니다. 이를 위해 paintComponent 메서드를 재정의합니다.
호출 순서:
JPanel.paint()JPanel.paintComponent()(여기서 배경 그리기)JPanel.paintChildren()(자식 컴포넌트 그리기)
예제 (BackgroundImageExample)
public class MyPanel extends JPanel {
private Image bgImage;
public MyPanel() {
setLayout(null);
bgImage = new ImageIcon(getClass().getResource("bg.jpg")).getImage();
// 자식 컴포넌트 추가
add(new JButton("버튼"));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // 기본 그리기 수행
g.drawImage(bgImage, 0, 0, getWidth(), getHeight(), this); // 배경 그리기
}
}