Transcript 강의 10

제 10주
그래픽프로그래밍2
제 10주 강의 목표
• Graphics를 사용하여 임의의 Shape을 그리는 법을 익힘
• 마우스이벤트 이용법을 익힘
• 타이머 이벤트 처리 및 애니메이션 효과를 구현하는 법을 익힘
객체지향프로그래밍
강원대학교
1
Frame
객체지향프로그래밍
강원대학교
2
import javax.swing.JFrame;
public class EmptyFrameViewer
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
final int FRAME_WIDTH = 300;
final int FRAME_HEIGHT = 400;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("An Empty Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
객체지향프로그래밍
강원대학교
3
도형 그리기
• 프레임 안에 도형을 그리기 위해서는 그림 그리는 기능을 가진 부품
(JComponent)을 프레임에 넣어주어야 함
• JComponent 객체는 paintComponent 메소드를 가짐
• paintComponent 메소드는 필요할 때마다 시스템에 의해 자동으로
호출됨
• 필요한 때
– 프로그램이 처음 실행될 때
– 프레임을 아이콘으로 최소화했다가 다시 창으로 복원시킬 때
– 프레임이 다른 윈도우에 의해 가려졌다가 나타날 때
– 마우스 드래그를 이용해 프레임을 이동시킬 때 등
객체지향프로그래밍
강원대학교
4
import javax.swing.*;
public class EmptyFrameViewer
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
final int FRAME_WIDTH = 300;
final int FRAME_HEIGHT = 400;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("An Empty Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent component = new JComponent(); // 부품을 구성
frame.add(component); // 부품을 프레임에 넣음
frame.setVisible(true);
}
}
객체지향프로그래밍
강원대학교
5
도형 그리기
•
•
•
JComponent 객체가 가지고 있는 paintComponent 메소드는 화면에 아무것
도 그리지 않음
화면에 도형을 그리려면 도형 그리는 기능을 갖도록 Jcomponent를 수정하
여 프레임에 넣어 줘야 함
Jcomponent를 수정하여 새로운 부품을 만드는 방법
public class RectangleComponent extends JComponent
{
public void paintComponent(Graphics g)
{
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
. . .
}
}
객체지향프로그래밍
강원대학교
6
RectangleComponent.java
public class RectangleComponent extends JComponent
{
public void paintComponent(Graphics g)
{
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
}
}
Rectangle box = new Rectangle(5, 10, 20, 30);
g2.draw(box);
• RectanlgeComponent 클래스는 수퍼클래스인 JComponent의
paintComponent 메소드를 상속하여 이를 재정의(override)함
• JComponent의 paintComponent 메소드는 아무것도 그리지 않음
• 재정의된 paintComponent 메소드는 사각형 인스턴스를 하나 구성하
고 이것을 화면에 그림
객체지향프로그래밍
강원대학교
7
RectangleViewer.java
import javax.swing.*;
public class RectangleViewer
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
final int FRAME_WIDTH = 300;
final int FRAME_HEIGHT = 400;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("A Rectangle Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
RectangleComponent component = new RectangleComponent();
frame.add(component); // 부품을 프레임에 넣음
frame.setVisible(true);
}
}
객체지향프로그래밍
강원대학교
8
RectangleComponent.java
import
import
import
import
javax.swing.JComponent;
java.awt.Rectangle;
java.awt.Graphics;
java.awt.Graphics2D;
public class RectangleComponent extends JComponent
{
public void paintComponent(Graphics g)
{
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
Rectangle box = new Rectangle(5, 10, 20, 30);
g2.draw(box);
}
}
box.translate(15, 25);
g2.draw(box);
객체지향프로그래밍
강원대학교
9
컴파일할 때의 파일간 종속성
• (같은 폴더에) RectanlgeComponent.java 파일 없이
RectanlgeViewer.java를 컴파일하려고 하면 안됨
• RectangleViewer가 RectangleComponet를 사용하기 때문
• 반면 RectanlgeComponent.java는 RectanlgeViewer.java 파일 없이
도 컴파일 가능
객체지향프로그래밍
강원대학교
10
Graphical Shapes
• Rectangle, Ellipse2D.Double, Line2D.Double 등
• API 문서에서 java.awt.Shape을 찾아보면 Shape에 속하는 도형들을 더
볼 수 있음
객체지향프로그래밍
강원대학교
11
Graphical Shapes
• Ellipse2D.Double은 Ellipse2D의 내부클래스(innerclass)임
• Ellipse2D.Double를 사용하기 위해서는
import java.awt.geom.Ellipse2D
Ellipse2D.Double ellipse = new Ellipse2D.Double(x, y, width, height);
g2.draw(ellipse);
Ellipse
객체지향프로그래밍
강원대학교
12
Drawing Lines
• To construct a line:
Line2D.Double segment = new Line2D.Double(x1, y1, x2, y2);
or,
Point2D.Double from = new Point2D.Double(x1, y1);
Point2D.Double to = new Point2D.Double(x2, y2);
Line2D.Double segment = new Line2D.Double(from, to);
• To draw the line:
g.draw(segment);
객체지향프로그래밍
강원대학교
13
Drawing Strings
g2.drawString("Message", 50, 100);
객체지향프로그래밍
강원대학교
14
Colors
• Standard colors: Color 클래스에 static 필드로 정의되어
있음
• Color.BLUE, Color.RED, Color.PINK etc.
• static 필드: 개별 인스턴스에 속하지 않고 클래스에 하나만
정의되는 필드
• 필드: 클래스 내부이면서 메소드 외부에 선언된 변수, 상수
, 객체
객체지향프로그래밍
강원대학교
15
칼라 사각형 그리기
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.fill(new Rectangle(0, 0, 200, 200));
g2.setColor(Color.YELLOW);
g2.fill(new Rectangle(50, 50, 100, 100));
}
객체지향프로그래밍
강원대학교
16
임의 칼라 사각형 그리기
Color(float r, float g, float b) – r, g, b는 0.0-1.0
Color(int r, int g, int b) - r, g, b는 0-255
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setColor(new Color(0.5f, 0.6f, 0.3f));
g2.fill(new Rectangle(0, 0, 200, 200));
g2.setColor(new Color(25, 200, 224));
g2.fill(new Rectangle(50, 50, 100, 100));
}
객체지향프로그래밍
강원대학교
17
복잡한 모양 그리기
객체지향프로그래밍
강원대학교
18
import javax.swing.JFrame;
public class CarViewer
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
final int FRAME_WIDTH = 300;
final int FRAME_HEIGHT = 400;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Two cars");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CarComponent component = new CarComponent();
frame.add(component);
frame.setVisible(true);
}
}
객체지향프로그래밍
강원대학교
19
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
public class CarComponent extends JComponent
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Car car1 = new Car(0, 0);
위치
int x = getWidth() - Car.WIDTH;
int y = getHeight() - Car.HEIGHT;
HEIGHT
Car car2 = new Car(x, y);
car1.render(g2);
car2.render(g2);
WIDTH
}
}
객체지향프로그래밍
강원대학교
20
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
public class CarComponent extends JComponent
{
public void paintComponent(Graphics g)
{
CarComponent에 그림을
Graphics2D g2 = (Graphics2D) g;
그리기 위한 도구
Car car1 = new Car(0, 0);
• getWidth, getHeight는 paintComponent
int x = getWidth() - Car.WIDTH;
를 실행하고 있는 CarComponent 객체에
int y = getHeight() - Car.HEIGHT;
호출됨
Car car2 = new Car(x, y);
car1.render(g2);
car2.render(g2);
}
• 윈도우 크기를 조정하면
paintComponent가 호출되고 자동차의
위치가 재계산됨 (프로그램을 실행한 후
마우스를 드래그하여 윈도우 크기를 바꿔
보세요!)
}
객체지향프로그래밍
강원대학교
21
복잡한 모양 그리기
객체지향프로그래밍
강원대학교
22
public class Car
{
public Car(int x, int y)
{
xLeft = x;
yTop = y;
}
public void render(Graphics2D g2)
{
g2.draw(body);
g2.draw(frontTire);
g2.draw(rearTire);
g2.draw(frontWindshield);
g2.draw(roofTop);
g2.draw(rearWindshield);
}
미완성!
public static int WIDTH = 60;
public static int HEIGHT = 30;
// static field
// static field
private int xLeft;
private int yTop;
// 인스턴스 필드
// 인스턴스 필드
}
객체지향프로그래밍
강원대학교
23
import
import
import
import
import
java.awt.Graphics2D;
java.awt.Rectangle;
java.awt.geom.Ellipse2D;
java.awt.geom.Line2D;
java.awt.geom.Point2D;
/**
A car shape that can be positioned anywhere on the screen.
*/
public class Car
{
/**
Constructs a car with a given top left corner
@param x the x coordinate of the top left corner
@param y the y coordinate of the top left corner
*/
public Car(int x, int y)
{
xLeft = x;
yTop = y;
}
객체지향프로그래밍
강원대학교
24
/**
Draws the car.
@param g2 the graphics context
*/
public void render(Graphics2D g2)
{
Rectangle body
= new Rectangle(xLeft, yTop + 10, 60, 10);
Ellipse2D.Double frontTire
= new Ellipse2D.Double(xLeft + 10, yTop + 20, 10, 10);
Ellipse2D.Double rearTire
= new Ellipse2D.Double(xLeft + 40, yTop + 20, 10, 10);
// The bottom of the front windshield
Point2D.Double r1
= new Point2D.Double(xLeft + 10, yTop + 10);
// The front of the roof
Point2D.Double r2
= new Point2D.Double(xLeft + 20, yTop);
// The rear of the roof
Point2D.Double r3
= new Point2D.Double(xLeft + 40, yTop);
// The bottom of the rear windshield
Point2D.Double r4
객체지향프로그래밍
강원대학교
25
Line2D.Double frontWindshield
= new Line2D.Double(r1, r2);
Line2D.Double roofTop
= new Line2D.Double(r2, r3);
Line2D.Double rearWindshield
= new Line2D.Double(r3, r4);
g2.draw(body);
g2.draw(frontTire);
g2.draw(rearTire);
g2.draw(frontWindshield);
g2.draw(roofTop);
g2.draw(rearWindshield);
}
public static int WIDTH = 60;
public static int HEIGHT = 30;
private int xLeft;
private int yTop;
}
객체지향프로그래밍
강원대학교
26
Reading Text Input
String input = JOptionPane.showInputDialog("Enter x");
double x = Double.parseDouble(input);
객체지향프로그래밍
강원대학교
27
마우스 이벤트 처리
객체지향프로그래밍
강원대학교
28
Mouse Events
• 마우스 이벤트를 처리하기 위해서는 마우스리스너를 사용
• 마우스리스너는 MouseListener 인터페이스를 구현해
야 함
public interface MouseListener
{
void mousePressed(MouseEvent event);
// Called when a mouse button has been pressed on a component
void mouseReleased(MouseEvent event);
// Called when a mouse button has been released on a component
void mouseClicked(MouseEvent event);
// Called when the mouse has been clicked on a component
void mouseEntered(MouseEvent event);
// Called when the mouse enters a component
void mouseExited(MouseEvent event);
// Called when the mouse exits a component
}
객체지향프로그래밍
강원대학교
29
마우스 리스너 구현과 등록
public class MyMouseListener implements MouseListener
{
// Implements five methods
}
MouseListener listener = new MyMouseListener();
component.addMouseListener(listener);
객체지향프로그래밍
강원대학교
30
Mouse Event 처리 프로그램 예
• RectangleComponentViewer
• 마우스를 클릭하면 그 위치로 사각형이 이동
객체지향프로그래밍
강원대학교
31
public class RectangleComponent extends JComponent
{
public RectangleComponent() {
box = new Rectangle(BOX_X, BOX_Y, BOX_WIDTH,
BOX_HEIGHT);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.draw(box);
}
public void moveTo(int x, int y) {
box.setLocation(x, y);
repaint();
}
private Rectangle box;
}
객체지향프로그래밍
강원대학교
32
public class RectangleComponentViewer
{
public static void main(String[] args) {
final RectangleComponent component = new RectangleComponent();
class MousePressListener implements MouseListener {
public void mousePressed(MouseEvent event) {
int x = event.getX();
int y = event.getY();
component.moveTo(x, y);
}
public void mouseReleased(MouseEvent event) {}
public void mouseClicked(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
}
MouseListener listener = new MousePressListener();
component.addMouseListener(listener);
JFrame frame = new JFrame();
frame.add(component);
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}객체지향프로그래밍
강원대학교
33
File RectangleComponent.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
import
import
import
import
java.awt.Graphics;
java.awt.Graphics2D;
java.awt.Rectangle;
javax.swing.JComponent;
/**
This component lets the user move a rectangle by
clicking the mouse.
*/
public class RectangleComponent extends JComponent
{
public RectangleComponent()
{
// The rectangle that the paint method draws
box = new Rectangle(BOX_X, BOX_Y,
BOX_WIDTH, BOX_HEIGHT);
}
객체지향프로그래밍
강원대학교
34
File RectangleComponent.java
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.draw(box);
}
/**
Moves the rectangle to the
@param x the x-position of
@param y the y-position of
*/
public void moveTo(int x, int
{
box.setLocation(x, y);
repaint();
}
객체지향프로그래밍
강원대학교
given location.
the new location
the new location
y)
35
File RectangleComponent.java
37:
38:
39:
40:
41:
42:
43:
44: }
private Rectangle box;
private
private
private
private
객체지향프로그래밍
static
static
static
static
final
final
final
final
int
int
int
int
BOX_X = 100;
BOX_Y = 100;
BOX_WIDTH = 20;
BOX_HEIGHT = 30;
강원대학교
36
마우스 리스너 구현
class MousePressListener implements MouseListener
{
public void mousePressed(MouseEvent event)
{
int x = event.getX();
int y = event.getY();
component.moveTo(x, y);
}
// Do-nothing methods
public void mouseReleased(MouseEvent event) {}
public void mouseClicked(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
}
• MouseListener 인터페이스에 정해져 있는 다섯개의
메소드를 모두 구현해야 함
객체지향프로그래밍
강원대학교
37
RectangleComponentViewer2.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
/**
This program displays a RectangleComponent.
*/
public class RectangleComponentViewer
{
public static void main(String[] args)
{
final RectangleComponent component
= new RectangleComponent();
// Add mouse press listener
class MousePressListener implements MouseListener
{
객체지향프로그래밍
강원대학교
38
RectangleComponentViewer2.java
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
public void mousePressed(MouseEvent event)
{
int x = event.getX();
int y = event.getY();
component.moveTo(x, y);
}
// Do-nothing methods
public void mouseReleased(MouseEvent event) {}
public void mouseClicked(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
}
MouseListener listener = new MousePressListener();
component.addMouseListener(listener);
객체지향프로그래밍
강원대학교
39
RectangleComponentViewer2.java
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45: }
JFrame frame = new JFrame();
frame.add(component);
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static final int FRAME_WIDTH = 300;
private static final int FRAME_HEIGHT = 400;
객체지향프로그래밍
강원대학교
40
타이머 이벤트 처리
애니메이션
객체지향프로그래밍
강원대학교
41
Processing Timer Events
•
javax.swing.Timer는 일정 시간 간격으로 액션이
벤트를 발생시킨다.
• 객체 상태를 일정 시간 간격으로 갱신하고자 할 때 사용
• 타이머에게 액션이벤트 리스너를 등록해 놓으면 액션이벤
트가 발생될 때마다 액션이벤트 리스너의
actionPerformed 메소드가 호출됨 - callback!
class MyListener implements ActionListener
{
void actionPerformed(ActionEvent event)
{
// 타이머에서 액션이벤트가 발생할 때마다
// 이곳에 적어주는 액션이 실행됨
}
}
객체지향프로그래밍
강원대학교
42
Processing Timer Events
• 액션 리스너를 타이머에 등록함
MyListener listener = new MyListener();
Timer t = new Timer(interval, listener);
t.start(); // 타이머 쓰레드 시작
등록
MyListener
actionPerformed
Timer
주기적으로 이벤트 발생
actionPerformed 메소드 실행 (callback)
객체지향프로그래밍
강원대학교
43
Example: Countdown
• Example: a timer that counts down to zero
객체지향프로그래밍
강원대학교
44
File TimeTester.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
import
import
import
import
java.awt.event.ActionEvent;
java.awt.event.ActionListener;
javax.swing.JOptionPane;
javax.swing.Timer;
/**
This program tests the Timer class.
*/
public class TimerTester
{
public static void main(String[] args)
{
class CountDown implements ActionListener
{
public CountDown(int initialCount)
{
count = initialCount;
}
객체지향프로그래밍
강원대학교
45
File TimeTester.java
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
public void actionPerformed(ActionEvent event)
{
if (count >= 0)
System.out.println(count);
if (count == 0)
System.out.println("Liftoff!");
count--;
}
private int count;
}
CountDown listener = new CountDown(10);
final int DELAY = 1000; // Milliseconds between
// timer ticks
객체지향프로그래밍
강원대학교
46
File TimeTester.java
35:
36:
37:
38:
39:
40:
41: }
Timer t = new Timer(DELAY, listener);
t.start();
JOptionPane.showMessageDialog(null, "Quit?");
System.exit(0);
}
객체지향프로그래밍
강원대학교
47
애니메이션 프로그램 기본 형식
class Mover implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
// Move the rectangle
}
}
ActionListener listener = new Mover();
final int DELAY = 100; // Milliseconds between timer ticks
Timer t = new Timer(DELAY, listener);
t.start();
객체지향프로그래밍
강원대학교
48
Accessing Surrounding Variables
• Inner 클래스의 메소드에서는 바깥 클래스의 변수에 접근할 수 있음
public static void main(String[] args)
{
. . .
final Rectangle box = new Rectangle(5, 10, 20, 30);
class Mover implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
// Move the rectangle
box.translate(1, 1);
}
}
. . .
}
객체지향프로그래밍
강원대학교
49
File TimeTester2.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
import
import
import
import
import
java.awt.Rectangle;
java.awt.event.ActionEvent;
java.awt.event.ActionListener;
javax.swing.JOptionPane;
javax.swing.Timer;
/**
This program uses a timer to move a rectangle once per second.
*/
public class TimerTester2
{
public static void main(String[] args)
{
final Rectangle box = new Rectangle(5, 10, 20, 30);
class Mover implements ActionListener
{
객체지향프로그래밍
강원대학교
50
File TimeTester2.java
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35: }
public void actionPerformed(ActionEvent event)
{
box.translate(1, 1);
System.out.println(box);
}
}
ActionListener listener = new Mover();
final int DELAY = 100; // Milliseconds between timer ticks
Timer t = new Timer(DELAY, listener);
t.start();
JOptionPane.showMessageDialog(null, "Quit?");
System.out.println("Last box position: " + box);
System.exit(0);
}
객체지향프로그래밍
강원대학교
51
File TimeTester2.java
Output:
java.awt.Rectangle[x=6,y=11,width=20,height=30]
java.awt.Rectangle[x=7,y=12,width=20,height=30]
java.awt.Rectangle[x=8,y=13,width=20,height=30] . . .
java.awt.Rectangle[x=28,y=33,width=20,height=30]
java.awt.Rectangle[x=29,y=34,width=20,height=30]
Last box position: java.awt.Rectangle[x=29,y=34,width=20,height=30]
객체지향프로그래밍
강원대학교
52
Animation Program
객체지향프로그래밍
강원대학교
53
public class RectangleComponent extends JComponent{
private Rectangle box;
public RectangleComponent(){
box = new Rectangle(BOX_X, BOX_Y, BOX_WIDTH,
BOX_HEIGHT);
}
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.draw(box);
}
public void moveBy(int dx, int dy){
box.translate(dx, dy);
repaint();
}
}
객체지향프로그래밍
강원대학교
54
public class RectangleMover{
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("An animated rectangle");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final RectangleComponent component = new RectangleComponent();
frame.add(component);
frame.setVisible(true);
class TimerListener implements ActionListener{
public void actionPerformed(ActionEvent event){
component.moveBy(1, 1);
}
}
ActionListener listener = new TimerListener();
final int DELAY = 100; // Milliseconds between timer ticks
Timer t = new Timer(DELAY, listener);
t.start();
}
}
객체지향프로그래밍
강원대학교
55