23
JAVA 프로그래밍 4. 그래픽 프로그래밍 한동일 2/46 학습 목표 To be able to write simple GUI applications To display graphical shapes such as lines and ellipses To use colors To display drawings consisting of many shapes To read input from a dialog box To develop test cases that validate the correctness of your programs

4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

JAVA 프로그래밍

4. 그래픽 프로그래밍

한 동 일

2/46

학습 목표

To be able to write simple GUI applications

To display graphical shapes such as lines and ellipses

To use colors

To display drawings consisting of many shapes

To read input from a dialog box

To develop test cases that validate the correctness of your programs

Page 2: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

3/46

Java Foundation Classes

JFC(Java Foundation Classes)

그래픽, 이미지 처리, GUI 등의 개발에 사용되는 클래스 들로 구성

AWT, Swing, Java2D, 접근성(Accessibility), 드래그 앤 드롭(Drag and Drop) 등의 영역으로 구성

AWT(Abstract Window Toolkit)

그래픽, 이미지 처리, GUI 등의 개발에 사용

관련 클래스들과 인터페이스들의 모임

4/46

AWT AWT의 기본적인 기능

기본적인 그래픽 생성

폰트 조작

이미지 처리

프린팅 기능

GUI 개발 기능

버튼, 리스트, 박스, 메뉴 등의 컴포넌트 생성

생성된 컴포넌트의 컨테이너 내 조직화

컴포넌트의 배치

이벤트 처리

Page 3: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

5/46

AWT

AWT의 단점

호스트 운영 체제에 의존

JVM을 지원하는 모든 컴퓨터에 일관된 룩앤필을갖는 GUI의 작성이 불가능

GUI의 모습이 세련되지 못함

특정 플랫폼의 고유한 특징이 포함 안됨

컴포넌트의 수가 적음

AWT의 기능 보완 => 스윙

6/46

스윙 AWT의 한계를 극복하기 위해 개발

스윙의 고유 컴포넌트

이미지를 포함하는 레이블과 버튼

툴바, 툴팁, 진행 상황을 표현하는 바

슬라이더, 리스트 등

J로 시작(JFrame, JLabel 등) – AWT와 구분

운영 체제에 독립적

자바 내에서 컴포넌트를 생성하고 관리

OS(Window, Solaris 등)에 무관한 룩앤필

Page 4: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

7/46

스윙

paint(Graphics g) 메소드의 기능을 보강

paintComponent(Graphics g) 메소드 추가

Graphics

추상 클래스

하위 클래스에서 구현된 메소드가 호출

Graphics2D

드로잉 공간의 모습을 다른 모습으로 변경하는 기능 제공

fill(), draw(), scale(), shear(), rotate() 등 다양한 기능 제공

8/46

AWT 드로잉 메커니즘 AWT(Abstract Window Toolkit, 추상 윈도우 툴킷)

자바의 그래픽 사용자 인터페이스

그래픽, 이미지 처리, GUI 등의 개발에 사용

관련 클래스들과 인터페이스들의 모임

색, 폰트, 도형, 컴포넌트 등을 제공

GUI 구성 예

Page 5: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

9/46

AWT : 컴포넌트

컴포넌트(Component Class)

그래픽 화면을 구성하는 구성요소

버튼, 텍스트 필드, 대화상자 등

java.awt.Component 의 하위 클래스

각 컴포넌트들은 자신의 모양을 스스로 그릴 수 있음

10/46

CardLayout

Object

CheckboxGroup

Button

Canvas

Checkbox

Label

List

Scrollbar

Panel

Window

MenuBar

MenuItem

FlowLayout

GridBagLayout

GridBagConstraints

BorderLayout

GridLayout GridLayout

Applet

Frame

TextField

TextArea

Menu

CheckboxMenuItem

Dialog FileDialog

Class

Choice

Object

CheckboxGroup

Component

MenuComponent

Container

MenuBar

FlowLayout

GridBagLayout

GridLayout GridLayout

Applet

Frame

Menu

Abstract class

CardLayout

WindowScrollPane

TextComponent

Page 6: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

11/46

주요 컴포넌트 및 기능(AWT)

12/46

스윙의 특징 스윙의 주요 특징

완전히 자바 내에서 컴포넌트를 생성하고 관리

호스트 운영체제에 종속되지 않음

모든 컴포넌트를 생성하고 드로잉하는 코드 제공

OS(Window, Solaris 등)에 무관한 룩앤필을 정의 가능

Windows, Solaris, 메킨토쉬 등의 룩앤필 정의 가능

AWT에 없는 기능 룩앤필 지정

느린 동작으로 그리기

풍선 도움말의 사용

더블 버퍼링의 지원

Page 7: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

13/46

스윙 컴포넌트들의 계층구조 AWT의 Container를 확장한 클래스들과 JComponent

클래스를 확장한 컴포넌트들로 구성

JComponent는 Container클래스를 확장

JComponent 클래스의 기능

이벤트 청취자 관리

이벤트 처리

마우스, 키보드에 반응

툴팁(Tool Tips)의 생성과 표시

포커스 처리

컴포넌트의 외형 처리

14/46

Object

Dimension ColorFontMetricsFont GraphicsComponent

Container

Panel Window

JComponent

Frame DialogApplet

JFrame JDialogJApplet

Button

Checkbox

TextComponentLabel

Choice

ScrollbarList Canvas

JTextComponent AbstractButton

JEditorPane JTextField JTextArea

JMenuItem JButton JToggleButtonJPasswordField

JMenu

JCheckBoxMenuItem

JRadioButtonMenuItem

JCheckBox

JRadioButton

JLabel JList JComboBox

JPanel

JOptionPane

JSlider

JScrollBar

JTabbedPane JSplitPane

JLayeredPane

JSeparator JRootPane JToolBar

JMenuBar JToolTip JPopupMenu JFileChooser

JColorChooser JTree JTable

JProgressBar

JTableHeader

JSpinner JInteralFrameJScrollPane

AWT

Swing

스윙 컴포넌트들의 계층구조

Page 8: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

15/46

JButtonJCheckBox

JComboBox JList

JSliderJRadioButton

JTextField

JTextArea

JSpinnerJPasswordField

스윙 컴포넌트들의 예

16/46

JProgressBar

JToolTip

JScrollPane

JApplet JFrameJDialog

JMenu

스윙 컴포넌트들의 예

Page 9: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

17/46

기본 스윙 컴포넌트 스윙을 이용한 GUI 구성 시 가장 기본이 되는 컴포넌트

JFrame, JButton, JLabel 클래스

JFrame

프레임 감추기, 닫기, 최대화, 최소화 등의 기능

레이아웃 관리자 지정

프레임 영역의 구성

경계, 메뉴바, 타이틀바, 컨텐츠

컨텐츠 부분은 컨텐츠 페인으로 표현

컨텐츠 페인 내에 보여줄 컴포넌트 배치

레이아웃 관리자가 컨텐츠 페인에 지정

18/46

기본 스윙 컴포넌트

JButton

스윙의 모든 버튼 클래스들은 추상 클래스인

AbstractButton 클래스의 하위 클래스

메뉴 항목도 하나의 버튼으로 간주

메뉴 항목의 클릭 시 버튼처럼 행동

JLabel

AWT의 단순 텍스트 형식 보완

스윙에서는 텍스트, HTML 포맷의 텍스트, 아이콘 구성 가능

Page 10: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

19/46

스윙 컴포넌트

모든 스윙 컴포넌트들은 컨테이너

JComponent는 Container의 하위 클래스

JSplitPane

하나의 프레임을 둘로 나눌때 사용

수평, 수직 분할 가능

초기 위치 지정 및 분할 위치 이동 가능

JDesktopPane, JInternalFrame

데스크탑 내에 존재하는 경량의 프레임 구성 가능

20/46

스윙 컴포넌트

AWT 컴포넌트에 대한 스윙 컴포넌트 제공

AWT와의 호완성 유지

AWT 클래스 이름에 J를 붙여서 사용

스윙 자체의 새로운 컴포넌트 추가

Page 11: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

21/46

스윙 컴포넌트 AWT에 대응되는 컴포넌트들

JButton, JMenuItem, JMenu, JCheckbox, JLabel, JList,

JMenuBar, JPanel, JPopupMenu, JScrollBar, JScrollPane,

JTextArea, JTextField, JApplet, JDialog, JFrame, JWindow

스윙 고유의 컴포넌트들

JRadioButton, JColorChooser, JComboBox,

JCheckBoxMenuItem, JRadioButtonMenuItem,

JInternalFrame, JSplitPane, JProgressBar, JSlider,

JTabbedPane, JPasswordField, JToolBar, JTree, JTable

http://download.oracle.com/javase/tutorial/uiswing/components/index.html 참고

22/46

프레임 윈도우의 생성 JFrame 클래스 : javax.swing package에 포함

import javax.swing.*; 이용

프레임 윈도우 생성 과정

1) JFrame 클래스의 객체 생성

JFrame frame = new JFrame();

2) 프레임 크기 설정

frame.setSize(300, 400);

3) 필요시, 프레임 제목 지정

frame.setTitle("An Empty Frame");

4) 디폴트 닫힘 연산 지정 :프레임 종료시 프로그램 자동 종료 위함

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

5) 프레임 보여줌

frame.setVisible(true);

Page 12: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

23/46

EmptyFrameViewer.java 실습

교재 60페이지의 EmptyFrameViewer.java code를 이해하고 구현하라.

실행 결과를 확인하라.

동시에 두 개의 프레임을 생성하라. 첫 프레임은 “An Empty Frame” 라는 제목 표시

두번째 프레임은 “Hello, World!” 라는 제목 표시

이때 아래의 API를 참고하라. JAVA API의 JFrame 클래스 참고

JAVA API의 Frame 클래스 참고

24/46

도형 그리기

추상 클래스인 JComponent를 확장 JComponent를 확장한 클래스에서 그려야 할 도형 생성

public void paintComponent(Graphics g): 자신의 도형을 생성하는 메소드

윈도우가 처음 생성되거나 다시 보여야 할 때 자동적으로 호출됨

사용자가 원하는 모양을 그리고자 할 때

paintComponent(Graphic g)를 재정의(overriding)

}

public class RectangleComponent extends JComponent {public void paintComponent(Graphics g) {

// Recover Graphics2DGraphics2D g2 = (Graphics2D) g;. . . //필요한 그리기 코드 작성

}}

Page 13: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

25/46

도형 그리기

Graphics 클래스 : 그리는 작업에 사용되는 색상, 폰트와같이 그래픽 생성에 필요한 정보와 메소드 제공

Graphics2D 클래스 : draw 메소드 보유 2차원 그래픽 객체를 그리기 위해 좀더 정교한 메소드가 필요할

때 캐스팅을 통하여 Graphics2D 클래스로 만들어 사용

좀 더 강력한 객체 지향 접근법 제공

java.awt.Graphics, java.awt.Graphics2D 클래스 참고

Rectangle box = new Rectangle(5, 10, 20, 30);g2.draw(box);

// draw(Shape s) vs. drawOval, drawPolygon, drawLine, etc.

26/46

컴포넌트 객체의 표현 예

RectangleComponent: paintComponent 메소드를 이용하여 2개의 사각형을 생성

RectangleViewer: 그림이 그려진 컴포넌트를 프레임에추가한 후 화면을 생성 프레임 생성

컴포넌트 클래스의 객체 생성

컴포넌트 객체를 프레임에 추가

프레임 보여줌

RectangleComponent component = new RectangleComponent();

frame.add(component);

Page 14: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

27/46

RectangleViewer.java 실습

강의 홈페이지의 RectangleComponent.java, RectangleViewer.java code를 이해하라. (교재 62, 63 페이지 참고)

실행 결과를 확인하라.

아래와 같이 출력되도록 코드를 수정하라. 두 개의 정사각형을 그려라.

하나의 직사각형과 하나의 정사각형을 그리도록 수정하라.

g2.draw(box) 대신 g.draw(box)를 호출하면?

Graphics2D 객체가 아닌 Graphic 객체를 이용하여RectangleComponent.java 를 구성하라.

JAVA API의 Graphics, Graphics2D 클래스 참고

28/46

Applet 이용한 도형 그리기

import java.applet.*; public class MyApplet extends Applet {

public void paint(Graphics g) {// Recover Graphics2DGraphics2D g2 = (Graphics2D) g;// Drawing instructions go here. . .

}}// import javax.swing.JApplet;를 import할 경우 JApplet을 확장

뷰어 클래스 불필요, 대신 HTML 파일 이용

애플리케이션 프로그램과의 차이 JComponent 대신 Applet를 확장

paintComponent 대신 paint 메소드에서 그림 그리는작업 수행

Page 15: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

29/46

그래픽 도형 원, 타원 그리기

import java.awt.geom.Ellipse2D; // no .Double

. . .Ellipse2D.Double ellipse = new Ellipse2D.Double(x, y, width, height);g2.draw(ellipse);

. . .

(0,0)X 축

Y 축

캔버스 구조

30/46

그래픽 도형

혹은 java.awt.Graphics 클래스에 있는 메소드 사용

원,타원 drawOval 메소드와 fillOval 메소드 이용

drawOval(20,20, 50,50); // 시작점, 폭, 높이

호(Arc) drawArc 메소드 이용

6개의 매개변수

처음 4개의 매개변수: 사각형을 그리는 매개변수 값과 동일

5번째 매개변수: 호를 그리기 위한 시작각

6번째 매개변수: 호의 중심각

g.drawArc(20,20,50,50, 90,180);

Page 16: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

31/46

그래픽 도형 선 그리기

텍스트 입력

Line2D.Double segment = new Line2D.Double(x1, y1, x2, y2);

// 혹은Point2D.Double from = new Point2D.Double(x1, y1);Point2D.Double to = new Point2D.Double(x2, y2);Line2D.Double segment = new Line2D.Double(from, to);

g2.drawString("Message", 50, 100); // 문자열과 기본점의 x, y 좌표

32/46

혹은 java.awt.Graphics 클래스에 있는 메소드 사용

선(Line) drawLine() 메소드 이용

g.drawLine(20,20, 80,80); // 시작점과 끝점의 x,y의 좌표

사각형(Rectangle)

일반적인 사각형, 둥근 모서리 사각형, 3차원 사각형 제공

drawRect() 메소드, drawRoundRect() 메소드

drawRect(20,20, 50,50); // 시작점, 폭, 높이

각 사각형에 대한 채워진 사각형을 그릴 수 있는 메소드 제

fillRect 메소드, fillRoundRect 메소드

그래픽 도형

Page 17: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

33/46

그래픽 도형

다각형(Polygon)

drawPloygon(Polygon p)

drawPolygon(int[] xPoints, int[] yPoints, int nPoints)

Polygon p = new Polygon();p.addPoint (30, 30);p.addPoint (5, 50);p.addPoint (40, 75);p.addPoint (70, 20);p.addPoint (35, 10);g2.drawPolygon(p);

// 혹은int[] xPnts = {30, 5, 40, 70, 35};int[] yPnts = {30, 50, 75, 20, 10};int nPnts = xPnts.length;g2.drawPolygon(xPnts, yPnts, nPnts);

34/46

그래픽 도형 색

java.awt.Color 클래스

객체 생성자

자바의 칼라 상수

Color.black, Color.green, Color.red, Color.blue, Color.lightGray, Color.white, Color.cyan, Color.magenta, Color.yellow,Color.darkgray, Color.orange, Color.gray, Color.pink

Color(int, int, int) // red, green, blue 순서Color(float, float, float)

Page 18: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

35/46

그래픽 도형

그래픽 객체의 색상 변경

도형의 내부를 색칠할 때

draw 메소드 대신 fill 메소드사용

g2.fill(rectangle); // filled with current color

g2.setColor(magenta);

36/46

그래픽 도형 폰트

java.awt.Font 클래스

제공 글꼴 Dialog

DialogInput

Serif

SansSerif

Monospaced

객체 생성자

Font(String name, int style, int size)// 글꼴 이름, 스타일(볼드, 이탤릭 등), 폰트 크기 정의

Page 19: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

37/46

텍스트 입력 JOptionPane 클래스를 통해 대화상자를 보여주고 사용자 입력 처리

가능

showInputDialog 를 사용하여 사용자 입력

showInputDialog는 사용자가 입력한 문자열을 리턴

필요시 문자열을 integer나 double 형태로 변환하여 사용

Integer.parseInt (String s) : 문자열을 integer로 변환

Double.parseDouble (String s) : 문자열을 double로 변환

String input = JOptionPane.showInputDialog("Enter x");double x = Double.parseDouble(input);

38/46

복잡한 모양 그리기 각각의 복잡한 모양을 독립된 클래스로 생성

복잡한 모양은 모눈종이에 스케치를 통해 좌표 파악

class Car {. . .public void draw(Graphics2D g2) {

// Drawing instructions. . .

}}

Page 20: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

39/46

[실습1] – House 그림 이해 강의 홈페이지의 HouseComponent.java,

HouseViewer.java code를 테스트하고 프로그램을 이해하라.

paintComponent 메소드 명을 다음과 같이 변경 후 테스트 하라.

paint

paintComp

출력이 달라질 경우 그 이유는 무엇인가?

house 폴더 및 오른쪽 그림 내용 참고

Applet을 상속받는 HouseApplet 클래스를

설계하고 같은 그림을 Applet으로 그려라.

40/46

[실습2] – Polygon 생성 실습 1의 코드를 수정하여 아래의 왼쪽 그림과 같은

polygon을 생성하라.

좌표는 다음의 정보를 사용하라. int[] xPnts = {30, 5, 40, 70, 35};

int[] yPnts = {30, 50, 75, 20, 10};

아래의 오른쪽 그림과 같이 polygon 내부에 적절한 색상을 지정하라.

Page 21: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

41/46

강의 홈페이지의 CarComponent.java code를 테스트하고 프로그램을 이해하라.

Car.java 파일을 수정하여 아래의 두 번째 그림처럼 차의본체나 바퀴 등에 적절한 컬러를 입혀라.

이후 CarComponent.java 파일을 수정하여 아래의 세 번째 그림처럼 3개 이상의 차를 생성하라.

복수개의 Car 생성을 위해서 이용한 세 java 코드의 구성을 이해하라.

[실습3] – Car 그림 생성

42/46

강의 홈페이지의 ColoredSquareComponent.java code를 테스트하고 다양한 컬러를 생성해보고 프로그램을 이해하라.

[실습4] – 텍스트 입력

Page 22: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

43/46

강의 홈페이지의 ClockComponent.java code를 완성하라. (아래 그림 참고)

[실습5] – 시계화면 생성

44/46

[실습6] – 동심원 생성 ClockComponent.java code를 변형하여 아래 그림과 같

은 동심원을 생성하라.

컬러를 변형하여 아래 그림과 같은 과녁판을 생성하라.

Page 23: 4. 그래픽프로그래밍 한동일 - SEJONGvip.sejong.ac.kr/dihan/java/lec04_05.pdf · JAVA 프로그래밍 4. 그래픽프로그래밍 한동일 2/46 학습목표 To be able to

45/46

[실습7] – Font의 사용 강의 홈페이지의 FontViewer.java code를 테스트하고

프로그램을 이해하라.

폰트의 종류와 크기, 위치등을 변경하여 다양한 종류의폰트들을 생성하라.

46/46

실습5와 실습7을 결합하여 다음과 같은 시계화면을 그리도록 ClockComponent.java code를 수정하라. (아래 그림 참고, 시각 폰트 정보 추가)

[실습8] – 시계화면 보강