2라운드. (자바 Graphics) 그림판 만들기!
by 줌코딩
1라운드를 마치자 마자 나온 2라운드 과제는 나만의 그림판을 만드는 것이다.
그림판 과제
기한 : 기한 : 6/21(오후8시) ~ 6/25(오후8시)
1.그림판(최소 4가지) -선, 사각형, 원, Polyline, Sketch(Pen), Spray, Pattern 2.속성(최소 2가지) -굵기, 색, Style, 채우기 3.부가기능(최소 2가지) -drag & drop, resize, rotate, undo/redo, 지우기, 저장/불러오기, 복사/붙여넣기, grouping/ungrouping
5일동안 코드를 몇번 엎고 다시 짜고를 반복한 결과 다음과 같은 결과물을 얻어냈다:)
구현해낸 기능은 다음과 같다.
가) 미리보기 기능
A. 툴바 가장 왼쪽에 위치한 미리보기는 도형을 그리기 위해서 설정한 선과 도형의 색상이 어떻게 그려질지 미리 보여주는 역할을 한다. B. 이는 그리기 앞서서 선과 도형의 조합을 미리 볼 수 있도록 해준다.
나) 그리기 기능
A. 이 그리기 툴에서는 직선, 사각형, 원, 폴리라인, 스케치 기능을 제공한다. B. 각각의 기능은 모두 툴바에 있는 버튼을 누르면 그릴 수 있게 되고 여러 회 그릴 수 있다. C. 해당 도형을 그만 그리고 싶다면 선택한 도형 버튼을 다시 클릭하거나 마우스 오른쪽 버튼을 클릭하면 DEFAULT모드로 다시 돌아갈 수 있다. D. 점을 선택한 후 다음 점을 선택할 때까지 잔상이 남도록 하였다. 다음 점을 선택하지 않는다면 그려지지 않는다.
i. 직선 그리기
- 직선이 그려진 이 버튼을 클릭하면 캔버스 상에 직선을 그릴 수 있다.
- 시작점에 마우스를 누른 후 드래그 하여 끝점에서 마우스를 놓게 되면 직선이 그려지게 된다.
ii. 사각형 그리기
- 사각형이 그려진 버튼을 선택한 후 시작점에서 마우스를 누른 후 드래그 하면 임의의 사각형이 그려진다.
- 끝점에서 마우스를 놓게 되면 사각형이 하나 그려진다.
iii. 원 그리기
- 원이 그려진 버튼을 선택한 후 한 점에서 마우스를 누른 후 드래그 하면 임의의 원이 그려진다.
- 끝점에서 마우스를 놓게 되면 시작점부터 끝점까지의 임의의 사각형을 채우는 원(타원)이 그려지게 된다.
iv. 폴리라인 그리기
- ‘>’ 모양이 그려진 버튼을 선택하면 굴곡진 선을 그릴 수 있다.
- 시작점에서 마우스를 클릭하고 꺾고 싶은 점에서 마우스를 왼쪽 마우스를 클릭해주고 마지막 점에서 오른쪽 마우스를 클릭하면 하나의 폴리라인이 만들어진다.
v. 스케치 그리기
- ‘⌇’ 모양이 그려진 버튼을 클릭하면 원하는 대로 그림이나 글씨를 쓸 수 있다.
- 마우스를 드래그하면 마우스를 따라 선이 그려지게 된다.
도형 그리기 버튼을 이용하여 그린 도형
다) Undo & Redo 기능
A. 도형 그리기 옆에는 방금 작업한 내용으로 돌아갈 수 있는 undo 버튼과 undo한 내용을 되돌릴 수 있는 redo 버튼이 있다.
B. Undo를 한 후에 무언가 그려지게 되면 undo 내용을 redo할 수 없으니 유의하기 바란다.
C. 도형을 움직이고 undo를 하게 되면 움직이기 전 상황으로 돌아가며 그 외에는 바로 앞선 도형이 그려지기 전 캔버스로 돌아가게 된다.
라) 지우개 & 지우기 기능
A. 지우개 버튼을 선택하면 지우개 사이즈를 선택할 수 있는 프레임이 뜨게 된다. 지우개는 버튼을 누른 후 드래그 하게 되면 동그란 지우개가 보여지며 지우개는 캔버스 배경과 같은 흰색으로 그려지게 되며 앞서 그린 도형들을 가리는 것이 가능하다.
B. 지우기 버튼은 캔버스 상에 있는 모든 그림을 지워준다.
지우개 크기를 선택하는 창
C. 둘 다 undo와 redo가 가능하다.
마) 펜, 채우기 색, 굵기 선택 기능 A. 펜, 색을 선택하게 되면 색 선택 창이 뜨게 되는데 이 창에서 색을 골라주면 선택에 따라 도형이나 선을 그릴 수 있게 된다. B. 선택한 색에 따라 미리보기 도형이 변하게 된다.
펜과 채우기 색을 고르는 창
바) 도형 움직이기 기능 A. DEFAULT인 상태에서 마우스로 그려진 도형을 선택 한 후에 옮기게 되면 도형을 원하는 곳으로 옮길 수 있다.
움직이기 기능을 이용하여 도형을 움직인 모습
사) 현재 상태 표시 기능 A. 좌측 하단에 보면 현재 마우스의 좌표와 현재 상태를 보여주는 패널이 있다. B. 현재 작업 모드가 무엇인지 볼 수 있다.
현재 작업 중인 마우스 좌표와 모드를 볼 수 있는 패널
그럼 어떻게 짰는지를 다음의 과정을 통해서 보자!!
이 프로그램은 자바 언어를 이용해서 개발되었다. 자바 내에 있는 패키지를 이용해서 작성하였는데 그래픽을 제공한 패키지로는 awt와 그림을 그리는 환경에는 swing 패키지가 사용되었다.
A. 환경 구성 a. Swing에서 제공하는 JFrame 창에 메뉴바를 보여주는 JMenubar과 그림을 그리는 판인 JPanel을 이용하여 추가하여 환경을 설정하였다. b. JMenubar에는 여러 버튼을 추가하여서 도형과 기능 선택이 가능하도록 하였다. c. 이 프로그램은 여러 자바 파일을 생성하지 않고 하나의 자바 파일에 subclass들을 두어서 하나의 JFrame에서 같은 필드를 공용할 수 있도록 하였다.
d. 프레임 안에 넣을 요소들을 인스턴스화 하여서 위와 같이 add명령을 이용해서 추가하고 각각의 요소들의 Location, Size, Background을 설정하였다.
B. 툴바 설정
a. 툴바를 설정 해준 후에 미리 보기 기능을 하는 사각형을 그리기 위해 JLabel을 추가해 줬다.
b. 툴바의 그림을 그리는 역할을 하는 버튼인 optionbtn을 추가해주었다. i. 이 그림 그리는 역할을 하는 버튼에 ButtonAction을 감지하는ActionListener를 추가해주었는데 버튼이 선택됨을 감지해주는 역할을 한다. c. 그리고 기능을 하는 버튼들에도 똑같이 setbtn에도 actionlistener을 추가해줬다. d. 두께를 설정하기 위해서는 spinner를 이용하였다. i. 스피너란 위와 아래 버튼이 있는 수치를 설정할 수 있게 해주는 도구이다. 이것을 통해서 글자 두께를 설정해주었다.
ii. 여기에도 changeListener를 연결해주어서 spinner가 값이 바뀔 때 마다 두께가 바뀔 수 있도록 설정해주었다. iii. 다음은 버튼이 눌렸을때를 위한 ActionListener이다.
D. 이 코드를 보면 버튼에 해당하는 문자열을 받게 되면 option을 바꿔주는 것으로 되어있다. 옵션을 위한 값들이 다음과 같이 public static final int로 위치하고 있다. E. 지우개 버튼을 누를 시에는 JSlider가 추가되어 지우개의 크기는 slider를 통해서 받을 수 있다.
F. 그리고 undo 와 redo를 위해서 각 undo한 도형을 담아 놓을 수 있는 redoshape stack을 만들어 놓고 그려진 도형이 담겨져있는 shape라는 stack에 넣고 빼고 할 수 있도록 하였다. i. Undo 버튼을 클릭시에는 Stack shape에 저장되어있는 가장 최근 원소를 pop()하고 pop()한 원소를 Stack redoshape에 저장해놓는 것으로 진행하였다. ii. Redo 버튼 클릭시에는 stack redoshape을 pop()해서 stack shape에 저장한 후 canvas의 repaint()를 진행해주었다.
C. 도형 저장소 설정
a. 도형을 담을 수 있는 클래스를 하나 생성하여서 그 안에 각 도형의 정보를 담아주었다. b. 각 과정에서 이 클래스를 이용한 인스턴스를 만들어서 stack에 저장하는 과정을 반복했다.
D. 캔버스 설정
a. 생성자에 마우스 리스너를 추가해서 마우스의 좌표를 가져오거나 마우스의 움직임을 받을 수 있도록 하였다. b. 캔버스는 JPanel로 repaint()시 자동으로 paintComponent(Graphics g){} 메소드가 실행된다. 그 점을 이용하여서 마우스 리스너에서 여러 값들을 받아서 그림을 그려야 할 떄가 오면 repaint를 진행하여 주었다. c. 색상을 선택하고 그리는 데에는 Graphics g라는 패러미터가 사용되었는데 이 g는 일종의 펜 같은 역할을 한다. 더 나아가 2DGraphics 는 두께와 채우기 색상까지 고를 수 있게 되어있어서 이 기능을 이용하여서 paintComponent(Graphics g)를 수행했다.
E. paintComponent 구성
a. paintComponent는 두가지로 나누어져있는데 매번 stack shape에 있는 저장되어있는 object를 하나씩 꺼내서 그려주는 역할을 하는 부분과 드래그 시의 상황을 그려주는 잔상 그리기 부분으로 나누어져있다. b. Repaint가 진행되면 먼저 shape에서 꺼낸 object에 저장된 myfillcolor, thick 정보를 이용하여 Graphics의 색상과 두께를 정하고 각 케이스 마다 fill, draw를 진행한다. 이 과정을 stack 끝까지 반복한다. c. 그 후에 마우스가 드래그 될 때마다 계속 repaint() 되면서 보내지는 정보를 이용해서 잔상을 그려주는 것을 진행한다.
F. 마우스 리스너 구성
a. MyMouseListener는 MouseAdapter라는 부모 함수를 두고 MouseMotionListener를 implement해서 abstract method(mouseDragged와 mouseMoved)를 override해주었다.
b. 먼저 mouse가 pressed 상태가 되면 현재 option이 무엇인지에 따라 다음 과정이 진행된다. i. option이 DEFAULT라면 도형 움직이기가 가능해지는데 이 때 마우스 프레스된 지점에 도형이 있다면 그 중 가장 최근 도형의 정보를 tempshape이라는 object에 저장한다. 그리고 dragged 상태가 되면 마우스 움직인 정도 만큼 도형이 움직일 수 있도록 구성하였다. ii. option이 도형 중 하나라면 newshape이라는 object를 생성해서 필요한 정보를 드레그와 프레스 과정을 통해 담을 수 있도록 하였다. c. 도형 그리는 과정은 다음과 같이 하였다. 각 과정은 마우스 pressed시 newshape이라는 object가 생성되고 모든 과정이 끝난 후에는 newshape을 stack shape에 넣어주도록 설정하였다. i. 라인은 pressed 될 때를 start로 하고 released 되는 지점을 end가 되게 하였고 drawline method를 이용해서 그렸다. ii. 사각형과 원은 pressed 될 때 start로 하고 released 되는 지점을 end로 하였다. 근데 end 값이 start보다 작으면 width와 height가 음수가 되기 때문에 start점을 네 모퉁이 중에 가장 왼쪽 상단 점으로 하고 width와 height를 math.abs를 이용해서 정해주었다. 그릴 때 사용한 메소드는 drawRect, drawOval이다. iii. 폴리라인은 매번 프레스 될 때 마다 point를 저장하고 마지막에 마우스 오른쪽 버튼을 프레스를 하면 끝이 난다. 사용한 메소드는 drawPolyline이다. iv. Sketch는 드레그를 이용해서 진행하였다. 드레그 할 때마다 점들의 정보를 받아와서 매번 drawLine을 진행하여 주었다.
단 시간 내에 프로그램을 만들다 보니 아직 구현 못한 기능들이 많다. 그룹핑, 복사/붙여넣기, 저장/불러오기 기능도 추가해보고 싶었는데 못하게 되어 아쉽지만 일단 처음으로 graphics를 이용하여 어느 정도 완성도 있는 프로그램을 만들어 봤다는 사실에 만족한다. 콘솔 창이 아닌 프레임이 생성되는 것도 신기했는데 프레임에 내가 도구를 추가해서 사용 가능한 기능을 갖춘 프로그램을 만들었다는 사실에 굉장히 보람차다. 다음 번에도 GUI를 이용한 무엇인가를 만들어보라고 하면 막막함만 있지는 않을 것 같다.
코드는 github에 게시해놨다.
Subscribe via RSS