728x90
	private JLabel x1L, y1L, x2L, y2L, z1L, z2L;
	private JTextField x1T, y1T, x2T, y2T, z1T, z2T;
	private JCheckBox fill;
	private JRadioButton line, circle, rect, roundRect, pen;
	private JComboBox<String> combo;
	private JButton draw;
	private Drc canvas;

 

우선 기본적으로 필요한 필드를 작성한다

 

이런 모양의 그림판을 만들거다

우선 창을 만든다
setD~ 저건 종료에 대한 디폴드메소드이다.
그림판의 윗부분에 해당하는 메뉴들을 만든다.
그림을 그려서 얻을 좌표를 기록하는 라벨과 텍스트를 만들고 
Panel을 만들어 패널에 올린다.
JPanel과 그냥 Panel은 비슷하다.
그리고 아래부분에 대한 필드를 생성하고
JPanel에 담는다

ButtonGroup는 라디오 버튼이 중복으로 눌리지 않게 해주는 메소드이다.

색은 배열에 담고 JComboBox를 이용해 세로로 나열하게 만든다.
그다음 컨테이너에 담아서 출력하면
가운데는 비어있는 그림판 틀이 완성된다

가운데에 그림을 그릴 공간은 canvas로 만들어야 하는데 위에 필드를 보면 Drc canvas가 있다.

canvas는 다른 클래스를 만들어 연결할 거니깐 일단 Drc클래스를 만들자
클래스를 만들고 Canvas를 상속하고 기본생성자를 만든다
근데 메인메소드가 있는 Ex클래스에 연결을 해야한다.
Ex클래스에는 
private Drc canvas;
필드를 만들었기 때문에 canvas로 연결이 되었다.

1.정보를 오갈 수 있게 Drc클래스에 Ex의 필드?를 만들고
2.Ex클래스에서 보낸 정보를 Drc가 받을 수 있게 만들자
Ex클래스에서 만든 private Drc canvas; 처럼 
private Ex ex를 만들어 Ex클래스의 정보를 가져올 수 있는 연결점 ex를 만들고

저쪽에서 받은 정보를 토대로 canvas에 그림을 그려야 하기 때문에 파라미터로 Ex ex를 해준다.

그리고 그림판이니깐 알아볼수 있게 배경색을 지정한다.
그리고 Ex클래스에서 알아볼수 있게 중간 부분에 Drc클래스의 객체 canvas를 만들고 container에 add한다.
그럼 그림판 틀이 완성된다.


그림그리기

틀을 만들었으니까 그림을 그리자.

그림판에 그림을 그리는 동작은 마우스로 이루어진다.
마우스를 클릭한 시점과 뗀 시점까지 좌표값을 통해서 그림을 그리고

마우스를 뗐을때 그림이 남아야한다.

일단 마우스의 동작을 선언하자

Ex클래스의 기본생성자에 필요한 이벤트를 익명으로 만든다.
마우스를 처음 눌렀을때 좌표가 필요하고,
마우스를 끌어서 마지막에 두번째 좌표가 필요하다.



마우스를 찍었을때 나오는 좌표값을 JTextField에 저장해야한다.
그래서 x1T,y1T의 좌표값을 mousePressed에서 구해야 한다.
setText()는 파라미터로 받는 값을 set(입력)해주는 메소드다.

e.getX()는 마우스의 동작(MouseEvent e)에 좌표를 얻어오는 메소드다.
이 두개를 합해서 x1T.setText(e.getX());에서
setText는 String타입을 받는데 e.getX()는 int값이니깐 +""를 넣어서 int타입을 String으로 형변환해준다.

그럼 사진과 같이 도형을 그릴때 필요한 첫좌표값이 입력된다.

이제 두번째 좌표를 구하자
이렇게 해주면 이제 그림에 필요한 첫 좌표와 두번째 좌표를 구했다.
근데 Ex클래스에는 paint()가 없어서 그림을 그릴 수 없다.

이제 Ex클래스에서 얻은 좌표를 Drc클래스로 보내서 그림을 그려줘야한다.

근데 필드에 private로 선언했기 때문에 그냥 보낼수 없다.
getter를 잡자.
Ex클래스에 있는 private로 선언한 필드값들을 가져와야 하니깐 getter클래스를 만들어 다른 클래스에서도 사용할 수 있게 만든다.
Drc 클래스에 그림을 그릴 canvas가 될거니깐 여기에 paint()만들어야 한다.

그리고 Ex에서 마우스를 통해 얻은 좌표값을 얻어오기 위해  지역변수를 선언하고 값을 받아온다.

예시)아래의 사진을 보면 나오는 x1의 값이 getter를 통해 위의 사진으로 간다

먼저 Ex클래스의 값을 받아올려면 연결점인 변수 ex를 사용한다.
그리고 x1의 좌표를 위해 미리 만든 getter중 getX1T()를 불러온다. 그리고 그곳에 있는 값을 가져오는 getText()를 사용한다.
(ex.getX1T().getText());를 하면 마우스로 찍은 x1의 값을 가져올 수 있다. 
그리고 이건 Sting타입이니깐 Integer로 변환한다.

trim()메소드는 빈칸을 없애주는 메소드이다.
근데 실행하면 이렇게 오류가 나온다.
이유는
윈도우창 실행 -> paint()가 callback 메소드라서 마우스를 찍기도 전에 x,y 값을 가져옴.-> 아무값도 없는데 가져가니까 오류

오류를 없애는 방법은 좌표의 textfield에 0을 미리 선언하는거다. 
이렇게 하면 오류가 사라진다.

이제 좌표를 얻어왔으니까 그림을 그려야 한다.
도형을 그려보자
Drc의 paint()에 도형에 대한 코드를 만들었다.

그림판을 보면 채우기를 했을때 와 안했을 떄 2가지의 경우가 있다.
그림을 보면 이해가 된다

isSelected()는 선택했다면 이라는 메소드다.

이 안에 x1, y1, x2, y2, z1, z2의 좌표를 잘 넣어보자
이렇게 넣으면 그림이 그려지긴 하는데
좌표값이 이상하게 찍히고 
왼쪽에서 오른쪽으로만 찍히고
그림을 하나 그리고 또 그리면 없어지고
색을 채우기해도 뭐 안생긴다.

여기서 z1,z2의값은 둥근 사각형에만 있는데 
이건 모서리의 굴절을 나타낸다
일단 50으로 고정한다.


이제 생각을 많이 해야한다.
x2,y2의 값은 시작점에서 드래그가 끝난 시점이다.
그럼 좌표의 값은 x2-x1,  y2-y1이 된다.

그다음 그림을 왼쪽->오른쪽 방향으로만 그릴게 아니라 양옆 위아래로도 다 되야 한다.
그럼 x1,y1값이 x2,y2보다 작아질수도 있고...
x2-x1한게 음수가 나올수도 있다.
일단 음수를 잡자
Math.abs()를 사용하면 된다

x2,y2의 값을 제대로 잡으니깐 왼쪽->오른쪽으로 만드는 것도 제대로 된다.

반대로그리는건....
드래그를 반대로 하니깐 x1가x2가 되버리고 y1이y2가 되버린다. 반대로 가면 대칭이니깐
그럼 두개다쓰고 최소값을 구하자
Math.min()


*drawLine은 그냥(x1, y1, x2, y2)로 해야한다...
이렇게 하면 그림은 이제 좌우, 위아래로 해도 잘그려진다.

이제 색을 채우자 
근데 색상을 필드로 지정해야 하는데 고정된 색은 상수로 만들면된다
enum으로 만들어보자
  채우기가 되는과정?
  코드를 짤때 순서를
좌표먼저하고 색을 채우고 도형을 그려야 한다.
그냥 만들때 뭘먼저 만들지 상관은 없지만 입력하는 순서를 다르게해서 
좌표, 도형, 색 이렇게 입력하면 첫도형을 그릴때 색이 안칠해진다.

enum으로 색을 정하고 switch로 색을 입력하는건 그냥....
색을 입력해야 되는 시점에 색상을 넣어줘야하는데 new color보다 상수로 하는게 더 편하고 확실하니까 상수로 하기로 결정한다.
그럼 어느 클래스에 만들지 결정하는데 아무데나 만들어도 상관은 없다.
그래서 shpaeDTO 클래스에 만든다.
shapeDTO는 그림을 그리고 다음그림을 그릴때 도형이 남을 수 있게 1개의 도형을 객체배열처럼 저장하기 위해 만든 클래스다.

 

728x90

'JAVA' 카테고리의 다른 글

10/23 수업내용  (0) 2020.10.23
10/22 수업내용  (0) 2020.10.22
10/19 수업  (0) 2020.10.19
10/16 수업내용  (0) 2020.10.16
스레드  (0) 2020.10.16
728x90
마우스를 뗀시점에 그림이 완성되고
그후에 그림정보를 저장해야하기 때문에 
mouseReleased를 만들어 도형을 저장할
ShapeDTO타입의 변수 dto를 new 해준다
그림을 그리고 안없어지게 할려면 그렸던 도형의 좌표, 채우기, 도형의 정보들을 
그림이 사라지는 시점인 마우스를 다시 클릭하기 전에
(repaint 하기전에)
shapeDTO로 저장해야 한다.
도형을 선택하고 드래그해서 모양과 크기를 잡고 마우스를 떼는 동작 mouseReleased에 값들을 저장해야 하니깐
이곳에 new를 해주고
좌표값들을 dto에 입력(set)해준다.
getText()를 하면 string타입이오고 그걸
integer.parseInt로 int타입으로 변환한다.

그럼 드래그해서 그린 그림의 정보가 
마우스를 떼면 DTO에 저장된다.
도형1개의 정보를 담을 dto를 만들었는데 담을 배열을 안만들었다.
도형1개의 정보가 담긴 dto를 담을 list를 필드에 만들고
list라는 변수를 만든다.
정보를 list.add(dto)로 저장한다
이렇게 list에 그린 그림들의 값이 저장되야 한다.
list.size를 통해 list에 저장된 것들을 확인할 수 있다.

이제 저장되는게 확인되니깐 화면에 그림이 남게 만들어야 한다.

그림을 그리는 메소드는 MsPaint클래스가 아닌 DrCanvas에 있다.
거기에 list가 안지워지게 list에 저장된 정보들을 처음에 출력할 수 있게 만들어야 한다.
for를 이용
근데 private으로잡았기 떄문에 getter를 만들어서
DrCanvas클래스에서 list를 사용할 수 있게 만든다
그리고 불러올 값들을 선언한다.

근데 아직 그리기 버튼을 완성 안했다

지금상태는 그림을 그리고 그리기를 안눌러도 저장이 된다.
그리기 버튼을 눌렀을때 저장이 될 수 있도록 
mouseReleased에서 작업을 해야한다.
이거는 클릭은 했는데 드래그를 안했는데도 도형으로 인식되서 list에 담기는걸 막는 코드이다.
새로잡은 x1,y1과 마우스를 클릭해서 얻은 좌표값이 같으면
움직이지 않은거니까 return;을 해서 그 밑에 있는 
ShapeDTO dto = new ShapeDTO();를 
실행하지 못하게 만든다.

연필기능 작성

펜기능은 mouseDragged에서만 일어난다.
근데 지금 이상태는 드래그를 할때
그려지고
rqpaint하고
그려지고해서 선을 드래그하는게 안남는다.
ShapeDTO dto = new ShapeDTO();를 입력해서
드래그해서 그린 것들을 저장하는 부분을 만들어야지
지워지지 않고 드래그한 정보가 남는다
윗부분 끌어다쓰고
펜추가
이게 마우스가 조금이라도 움직여서 좌표가 1이라도 변경되면 첫번째 줄부터 add까지가고
그다음에 x1t,y1t에 x2t,y2t값을 넣고
다시 생성하고 
반복하면서 그전에 그린 기록을 남기면서 그려나간다.

add가 계속 되면서 list에 저장된 배열의 수가 계속 늘어난다.
 consol창을 확인해보면 펜으로 그리고 도형을 그려보면 
배열의 수가 몇백으로 늘어난걸 볼 수 있다.

여기까지 하면 펜이 동작하는데 움직일떄마다 repaint되서 번쩍거린다
그걸 잡는 과정

더블버퍼

지금까지 화면에다 직접 그려서 깜빡거린건데 지금부터 할거는 다른데다 그려서 옮기는 과정이다.
다 그리고 마지막에 옮기기 때문에 번쩍거리지 않는다.

똑같은 크기의 canvas를 버퍼에 만들고 그림을 그린다음에 
마지막에 원래의 canvas로 옮긴다.

좌표생성하고 그림그리고 뭐하고 한거를 
버퍼에 만든다. 
이건 콜백 메소드라서 repaint할때불린다.
update()-paint()순으로 호출한다.
근데 지금까지는 update클래스를 안만들었기 때문에
바로 paint()로 갔다.
작동 순서가 이렇게 된다.
bufferImage는 파란색 그림판이고
bufferG는 그위에 그린 이미지다
먼저 paint에 있던 것들을 전부 upate로 옮겼따
먼저 필드 설정
getSize는 기존의 그림판 사이즈를 그대로 가져온다.


기존의 g를 모두 bufferG로 바꾼다

 

paint()에 코드를작성하면
update에서 그린 이미지판을 그대로 paint에 붙여넣기한다. 

 

선을 그릴때 반짝임을 없앨려면 저렇게한다
근데 선은괜찮은데 도형을 만들때 잔상이 남는다.
잔상을 지우기 위해서 
일단 그림을 그리면 무수히 많은 잔상이 생기고
잔상 한개당 캔버스만한 바탕색의 이미지가 그위에 덮혀지고 
마지막 그림만 남겨진다.
   

지우는 과정은 그린걸 없애는게 아니라 바탕색으로 덧칠하는 과정이다.



IOExcetion

값을 저장하고 한번에 읽은건데
일단 data.txt에 있는 정보를 배열에 저장하고 읽을 거다
 
나온다
   


일단 창생성
이렇게 만들거다
창에 menu을 만들거다
새로운 클래스를 만들어 그림처럼 만든다


메인창에 코드를생성해서 연결하면
결과가 나온다
이렇게 하면
이렇게 생긴다

버튼에 동작을 넣자
implement하고
이벤트가 많아질거니까 따로 메소드를 만들고
메인메소드에 작업을 한다

이렇게 하면 종료가 먹힌다

근데 MenuPane에 각 메뉴들을 private로 만들었기 때문에 getter를 만들어야 한다.
각 버튼에 대한 이벤트를 만들거니까 다 만들어 준다.
메뉴에 맞는 메소드 구현
다 만들어져 있따
단축키는 이렇게 넣는다
외우자
ctrl을 사용하면 윈도우랑 겹쳐서 동작이 되는지 안되는지 모른다.
alt로 하자


종료 구현은 디폴트 값을 먼저 설정해야 한다.

JFrame은 종료버튼을 누르면 완전히 종료되는 것이 아니라 윈도우창은 숨겨지고  consol은 실행되는 중이다.

그래서 setDefaultCloseOperation()라는 메소드를 선언하고 종료에 대한 디폴트값을 설정해줘야 한다.

기본생성자에 선언을 하는데
EXIT_ON_CLOSE와 DO_NOTHING_ON_CLOSE 두가지가 있다.

EXIT_ON_CLOSE를 하면 무슨 버튼을 누르든 항상 종료가 되고

DO_NOTHING_ON_CLOSE를 하면 종료확인에만 종료가 되고 취소버튼에는 종료가 되지 않는다.


종료버튼 활성화

ActionListener의 메소드를 오버라이드 한 곳에서 exit를 찾는다

종료에 관한 메소드를 구현해준다.
YES_NO_CANCEL_OPTION이 enum으로 상수로 설정되어있는 메소드이다.
차례대로 yes는 0, no 는 1, cancel은 2으로
if문을 통해 각 상황에 맞게 구현한다.

이 부분은 메뉴에서 종료를 눌렀을때 나오는 팝업이고

 

이 부분이 윈도우에서 x창을 눌렀을 때 나오는 팝업이다.
728x90
728x90

JTable2


DrCanvas

MsPaint클래스에서 DrCanvas클래스로 정보를 주고받는 방법

getter를 미리 만들어야 한다.

1

2


3

4

 

마우스를 누르는 시점이 x1 y1이다
100 - 250하면 음수가 나와서 오류가 난다.
절대값을 해줘야한다.
근데 절대값으로 잡아줘도 시작보다 커지기 때문에 그림이 파란색퍼럼 반대로 그려진다.

시작값을 변경해줘야한다. 작은 값을 시작으로 잡아야 한다.


시작점을 고정이아니라 x1,x2중 최소값을 정해주는 메소드를 한다.
   

도형를 연속으로 그릴려면 정보를 저장해야 하는데
x,y,z값, 채웠는, 무슨모양인지 다 기억해ㅑㅇ 한다.
이럴때 DTO를 사용

그리고 DTO정보를 list에 저장해야 한다.

 


IO Stream

Input output의 stream
데이터가 들어오고 나가는길
입출력 기능을 하는 메소드이다.

BufferedOutputStream
DataOutputStream
PrintStream

printStream이 더 사용하기 편해서 더 많이 사용한다.

DataOutoutStream을 사용
Buffer~ 저거는 바이트단위로 출력해서 한글이 깨진다.
 

데이터 입출력 순서


ByteStream

 

출력때 (char)로 안하면 나타나는 결과

char 했을때

728x90

'JAVA' 카테고리의 다른 글

10/22 수업내용  (0) 2020.10.22
그림판  (0) 2020.10.20
10/16 수업내용  (0) 2020.10.16
스레드  (0) 2020.10.16
10/15 수업내용(타이머,  (0) 2020.10.15
728x90

스레드 동기화

synchronized.class
ATMTest.class

 


싱글톤

변수명을 보통쓰던 aa, bb가 아닌 instance로 만든다

 
 

여러 클래스가 하나를 가르킨다


SWING

text 구역만들기
단점은 스크롤바가 자동으로 안생긴다.

스크롤바생성

 
 

JList


Vector

Vector은 ArrayList와 동일 한 내부구조를 가지고 있다. 
vector를 생성하기 위해서는 저장할 객체타입을 타입 파라미터로 표기하고 기본 생성자를 호출하면 된다.

List<E> list = new Vector<E>();

ArrayList와 다른 점은 Vector는 동기화된(synchronized) 메소드로 구성되어 있기 때문에 
멀티스레드가 동시에 이 메소드들을 실행할 수 없고
하나의 스레드가 실행을 완료해야만 다른 스레드를 실행할 수 있다.
그래서 멀티스레드 환경에서 안전하게 객체를 추가, 삭제할 수 있다.

728x90

'JAVA' 카테고리의 다른 글

그림판  (0) 2020.10.20
10/19 수업  (0) 2020.10.19
스레드  (0) 2020.10.16
10/15 수업내용(타이머,  (0) 2020.10.15
팩맨 움직이기1  (0) 2020.10.14
728x90

운영체제는 두가지 이상의 작업을 동시에 처리하는 멀티 테스킹을 할 수 있도록
CPU 및 메모리 자원을 프로세스마다 적절히 할당해주고 병렬로 실행시킨다.
예를 들어 워드로 문서작업을 하면서 '동시에' 미디어 플레이어로 음악을 들을 수 있다.

운영체제만이 아닌 하나의 어플, 프로그램도 멀티테스킹을 할 수 있다. 영상과 음악이 같이 나오는 미디어플레이어나
채팅을 하면서 파일도 전송하는 메신저가 그 예다. 
이런 동작을 멀치 스레드라고 한다

스레드는 하나의 코드 실행 흐름이다.

자바의 모든 애플리케이션은 메인스레드가 main()메소드를 실행하면서 시작한다.
우리가 간단하게 메인메소드에 System.out.println("Hello World")를 출력하는것도 하나의 스레드이다.

대략 그림으로 표현하면 이렇게된다. 스레드는 만들기 나름이다...


용어

테스크(Task)는 일 혹은 작업이라고 하며 프로세스와 스레드 까지 의미한다.

프로세스(Process)는 OS로부터 자원을 할당받아 동작하는 독립된 프로그램을 의미한다.

스레드(Thread)는 하나의 프로세스에서 실행하는 작업의 단위다.

멀티 태스킹은 여러개의 태스크 즉 일을 병렬처리 하는 것을 의미한다.

멀티 프로세싱은 여러개의 CPU 프로세스가 서로 협력하여 작업을 병행처리하는 기법이다.

멀티 스레딩은 하나의 프로그램(프로세스)에서 여러 개의 스레드가 실행되는 것을 의미한다.


스레드를 생성하기 위해선 Thread클래스와 Runnable 인터페이스가 필요하다

Thread 객체를 만들고 start()메소드를 실행하면 간단히 새로운 실행 흐름이 생성된다.
하지만 위에서 생선한 Thread 객체는 아무 동작도 하지 않기 때문에 아무런 결과를 얻을 수 없다.
즉, 아무일도 하지 않는 스레드가 생성되고 바로 소멸된 것이다.

작업을 수행하는 스레드를 만들기 위해서는 Thread 클래스의 run()메소드를 오버라이딩 해야한다.
run()메소드는 새로운 실행 흐름에서 수행한 작업이 정의된다.

위의 사진 play2는 첫번째와 달리 메세지를 출력한다. 
아래꺼는 Thread를 상속받고있고 run()메소드를 오버라이딩해서 새로운 일을 하도록 재정의했다.

Play3 클래스를 보면 Thread 객체 t의 start()메소드를 실행한 것을 볼 수 있다.
스레드를 실행하기 위해서는 스레드 객체를 생성하고 start()메소드를 호출해야 한다.

Thread클래스를 상속한 Play2 클래스의 경우 그 자체가 Thread클래스다

반면 인터페이스를 구현한 Play3 클래스의 경우 객체r을 인자로 넘긴다. 이떄 스레드 객체는 생성되었지만 start()메소드를 호출하기 전까지 아무 일도 일어나지 않는다. start()메소드를 호출해야 실행된다.

Play2와 Play3에서 사용한 구현 방식의 동작은 동일하다.
자바는 단일 상속만 가능하므로 상속을 한경우 확장성이 떨어진다.
반면 인터페이스를 구현한 경우 다형성 측면에서 유리하다. 즉 재사용 및 확장에 좋다.


스레드는 내가 동작하고 싶은 곳에 선언하면 된다.

타이머 클래스의 경우 메인메소드가 실행되는 도중에(윈도우창) 타이머를 동작할 거니까
마우스로 버튼을 누르는 동작에서 스레드를 발생시면되고 

스탑버튼을 누르는곳에선 스레드가 시작이 아닌 끝나는 t에다 null값을 넣으면 된다.


 

이 클래스같은 경우에는 버튼을 마우스로 '누르고 있으면' 동작해야 하니까 mousePressed에 스레드를 구현하고
버튼을 '떼는' 동작 mouseReleased에 스레드t를 제거하기위해 null을 선언

728x90

'JAVA' 카테고리의 다른 글

10/19 수업  (0) 2020.10.19
10/16 수업내용  (0) 2020.10.16
10/15 수업내용(타이머,  (0) 2020.10.15
팩맨 움직이기1  (0) 2020.10.14
10/14 수업  (0) 2020.10.14
728x90

팩맨 먹이 범위

 


x,y좌표를 랜덤으로 뽑는데 이거는 이미지가 작으니까 

빨간점 부분의 좌표를 생성한다.
만약 이미지가 크면 팩맨이 먹는 그림이 이상하니까 좌표를 다시설정해야 한다.

이미지 5개 생성

팩맨이 먹이 이미지를 지나치면 먹이가 없어져야 하기 때문에 동시 동작이 이뤄지는 쓰레드의 추상메소드인 run부분에 선언해야 한다.
먹이가 나타나는건 위에 paint에서 생성을 했고
여기선 먹이를 지우는걸 한다.
x+25,y+25를 한 이유는 이 x,y는 팩맨의 좌표다 

저 가운데의 좌표가 먹이 이미지 좌표랑 같으면 먹이좌표를 -100으로 해서 안보이게 이동시키는거


경주

1. 창만들고
2. 출발버튼만들고
3. 판넬에 올리고
4. 말그림 클래스따로 만들어서 캔버스로 그리기
5. 메인클래스 판넬에 올리기
6. 라인그리고
7. 이동시키고

 

 


스레드 - join()


Timer 타이머 만들기

 

이런 모양에 시작을 누르면 100까지 올라가고
정지를 누르면 멈추고
다시 시작을 누르면 초기화해서 올라가는 타이머 만들기

1.일단 윈도우 창에 버튼까지 만들기

버튼은 아직 활성화를 안했다.

2. 버튼을 누르면 동작할 수 있게 ActionListener 추가하고 쓰레드 생성하기

이제 Runnable을 implement하고 쓰레드를 추가해야 한다.


먼저 스레드를 실행하기 위해 추상클래스 Runnable을 implement하고

스레드(동작)을 작동할 위치에 스레드를 생성한다. 버튼을 클릭하면 스레드를 생성해 시간을 움직일 거기 때문에 액션리스너에 스레드를 생성했다.

그리고 오버라이드된 run메소드에 스레드가 넘어가서 동작할 기능을 구현한다.
타이머는1~100까지 할거니깐 for문을 만들고
숫자는 위에보면 label에 0으로 써놨는데 이게 int가 아니라 String타입이다. 그래서 문자열에 글자를 빼오는 setText()를 사용했다.

for문으로 증가하는 i를 선언하고 setText(i)를 넣으면 i
setText()에는 문자열이 들어가야하는데 i는 숫자니깐 '+""'를 해줘서 문자열로 변환시킨다.

그리고 너무 빠르니깐 슬립을 걸어서 동작을 늦춘다.
실행하고 시작을 누르면 이렇게 동작하는데 
시작을 한번더 누르면 스레드가 또 시작되서 섞인다.
그리고 정지버튼도 안먹힌다.

정지버튼을 구현하고 중복도 막자.
boolean형태인 aa를 만들어 기준점을 만든다
T면 시작, F면 정지

if(!aa)break; 의 뜻은
aa가 T일때 !(부정)을 만나 F가 되어 if문을 만족하지 않아 실행안하고 넘어간다.

aa가 F일때 !(부정)을 만나 T가 되어 if문을 만족해 break를 실행한다. 

그니까 정지버튼을 눌러 F가 되면 if문을 만족해 break를 실행해서 멈춘다.

근데 이상태에서 정지를 눌러도 스레드는 죽지않고 살아있다.
그래서 정지부분에 t=null을 넣어서 스레드 t를 초기화해서 멈춰준다.

근데 아직도 시작을하고 또 시작을 누르면 스레드가 또 발생한다. 그냥 못누르게 막아버리자.
startBtn.setEnabled(true);
stopBtn.setEnabled(false);
이 메소드가 버튼을 활성화하고 비활성화 시키는 메소드이다.
이걸 적절한 곳에 넣어준다.
그럼 완성
728x90

'JAVA' 카테고리의 다른 글

10/16 수업내용  (0) 2020.10.16
스레드  (0) 2020.10.16
팩맨 움직이기1  (0) 2020.10.14
10/14 수업  (0) 2020.10.14
미완성[메소드]정렬 sort(), Comparable vs Comparator  (0) 2020.10.14
728x90

처음 창을 만들고 종료버튼 활성화하기


이미지불러내서 윈도우창에 그리기
근데 저 이미지는 팩맨 한개가 50*50사이즈이고 여러개를 이어붙인 이미지이다.

크기는 0,0~ 400,50짜리 사이즈이고
각 그림의 좌표는 저렇게 된다.
이제 화살표를 누르면 사방으로 입을 벌리는 동작을 만들것이다.
근데 이미지는 저 하나로 사용할 것이다.
방법은 전체 이미지를 불러내서 보이고싶은 부분의 좌표만 입력하면 된다.
일단 왼쪽으로 입을 벌리고 있는 이미지를 불러보자 좌표는 0,0~ 50,50짜리다
그림을 그리는 g.drawImage메소드중에서 위에 그림처럼 4개짜리 파라미터 말고 더 많은걸 사용해야 한다.

바로 이것이다.

이렇게 사용하면되고 화면위치는 500*500이고 우리가 쓸 이미지의 크기는 50*50이니까 반쪼개고 쪼개서 계산하자

그럼 이렇게 우리가 생각한 이미지가 가운데 딱 뜬다
이제 저걸사방으로 벌리려면 원본이미지에서 그에맞는 좌표들을 따야한다.
그전에 일단 키보드 입력을 추가하자

추상메소드 implement하고 오버라이드하고 키를 동작하게 하는 이벤트도 추가한다.
먼저 esc를 누르면 종료될 수 있도록 만들었다.
이제 반향키에 대한 동작을 만들자

근데 paint부분에 좌표를 저렇게 찍어놓으면 값을 변경시키기 어렵기 때문에 이미지 위치의 좌표를 변수로 만들자
근데 이미지는 y값은 50으로 고정이기 때문에 x좌표는 sel이라는 변수로 만든다.

좌표에 맞는 x=sel 값을 넣고 키를 누르고 나면 다시 돌수 있도록 repaint()를 해준다.
repaint()를 안하면 그림이 움직이지 않는다.
근데 입까지 다물려면 이제 sel이 50,150,250,350도 필요하다

이렇게 sel을 다시 설정하면 더 편해진다. paint에 저렇게 만들면 이제 입을 열고있는 좌표들은 짝수이고
입을 닫고 있는 그림의 좌표는 홀수가 된다.
저기다 반복문 넣고 뭐하면 되겟지만 스레드를 이용하면 더 쉬워진다.

스레드 implement하고 저렇게 나누면된다.
그리고 try catch를 해준다. 이걸 안하면 동작이 0.01정도로 이뤄져서 바뀌는게 보이질 않는다.
저 예외처리를 해주면 슬립, 멈추는 시간을 정해줄 수 있다.
그리고 if문을 해줘서 sel을 나눠서 짝수면 ++로 하나를 더해서 입다물고 있는 사진(홀수)좌표를 바로 불러내고
sel이 다시 홀수가 되면 --해서 입을 열고 있는 짝수좌표로 바꾼다.
그리고 rqpaint()를 저기로 옮겨야지 이미지가 계속 갱신이 되면서 입을 뻐끔거린다.
(난 이건 못했다)
이제 좌우로 움직이게 만들자

이미지위치 좌표를 xy로 잡고 저렇게 하면 방향키 한번 누를때마다 이동

그리고 이제 아래에 완성된 코드까지만 하면 한번 누르면 한 방향으로 계속 가는 동작 구현 가능.
package exception;

import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class PackMan_02 extends Frame implements KeyListener, Runnable{
	private Image img = Toolkit.getDefaultToolkit().getImage("pacman.png");
	private int sel = 0;
	private int x=225;
	private int y=225;
	private int mx,my;
		
	public PackMan_02() {
		
		setBounds(800, 100, 500, 500);
		setVisible(true);
		setResizable(false);
		
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		addKeyListener(this);
		
		Thread t = new Thread(this);
		t.start();	
		
	}
	
	@Override
	public void paint(Graphics g) {
		g.drawImage(img, 
				x, y, x+50, y+50,
				sel*50, 0, sel*50+50, 50,
				this);
	}
//Runnable------------------------------------------------	
	@Override
	public void run() {
		while(true) {
			if(sel%2 == 0) sel++;
			else sel--;
			
			x += mx;
			y += my;
			if(x>500) x=0;
			else if(x<0) x=500;
			else if(y>500) y=0;
			else if(y<0) y=500;
			
			repaint();
			try {
				Thread.sleep(100);//기본이 1/1000초
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}		
	}	
//KeyListener------------------------------------------------
	@Override
	public void keyPressed(KeyEvent k) {
		if(k.getKeyCode() == KeyEvent.VK_ESCAPE) {
			System.exit(0);
		}else if(k.getKeyCode() == KeyEvent.VK_LEFT) {
			sel = 0;
			mx= -10; my=0;
		}else if(k.getKeyCode() == KeyEvent.VK_RIGHT) {
			sel = 2;
			mx = +10; my = 0;
		}else if(k.getKeyCode() == KeyEvent.VK_UP) {
			sel = 4;
			mx = 0; my = -10;
		}else if(k.getKeyCode() == KeyEvent.VK_DOWN) {
			sel = 6;
			mx = 0; my = +10;
		}	
	}
	@Override
	public void keyReleased(KeyEvent k) {	}
	@Override
	public void keyTyped(KeyEvent k) {	}
//--------------------------------------------------------


	public static void main(String[] args) {
		PackMan_02 p2= new PackMan_02();
	}
}


팩맨 먹이먹기

일단 방향키 누르면 한방향으로 쭉 가는 팩맨을 만들었다. 이제 먹이를 만들고 그 위를 지나가면 먹이를 먹은거처럼 만들자
먼저 먹이를 깐다.

먹이는 프로그램이 실행될때 랜덤으로 깔려야하니까 random메소드를 이용하면된다. 먹이는 5개를 깔꺼니깐 
x,y죄표를 담을 배열을 만들어 난수를 발생하는 객체를 넣자.
그래야 실행할때마다 좌표가 달라지니깐

이렇게 만들면 x와y가 난수로 5개 생긴다.
이제 이걸 paint메소드에 넣자

drawImage에 넣는데 배열값을 넣어야 하니까 배열을 돌릴수 있게 for를 이용한다.

이제 팩맨이 먹이 위를 지나가면 먹이 이미지가 없어지게 만들자.

우리가 먹이 이미지를 쓰기위해 만든 좌표의 위치는

저 빨간부분이다.
그리고 팩맨이 먹이 이미지를 지나치면 먹이가 없어져야 하기 때문에
동시 동작이 이뤄지는 쓰레드의 추상메소드인 run부분에 선언해야 한다.

먹이가 나타나는건 위에 paint에서 생성을 했고
run에선 먹이를 지우는걸 한다.

근데 앞서 만든 팩맨의 좌표도 먹이 이미지랑 똑같이 모서리를 가리키는 좌표다.
저 좌표를 사용해서 먹는걸 구현하면 이상하기 떄문에 팩맨의 중앙쯤이 먹이를 지나치면 
먹이 이미지가 사라지게 만들자.
x+25,y+25가 팩맨의 가운데 좌표다 

이렇게 하면 된다.

x+25>=foodX[i] && y+25>=foodY[i] 는

이 상황을 뜻한다.

그림을 보고 생각해보자


완성된 코드

package exception;

import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;


public class Packman extends Frame implements KeyListener, Runnable{
	private Image img;
	private Image foodImg;
	private int sel=0;
	private int x = 225;
	private int y = 225;
	private int mx, my;
	private int[] foodX, foodY;
	

	public Packman() {
		img = Toolkit.getDefaultToolkit().getImage("pacman.png");//이미지 불러오기
		foodImg = Toolkit.getDefaultToolkit().getImage("food.jpg"); 
		//food를 5개 만들 배열 생성
		foodX = new int [5];
		foodY = new int [5];
		//food가 생길 먹이 좌표 랜덤값 생성
		for(int i =0; i<foodX.length;i++) {
			foodX[i] = (int)(Math.random()*401)+50;//50~450
			foodY[i] = (int)(Math.random()*401)+50;//50~450
			System.out.println(foodX[i]+","+foodY[i]); 
		}//for
		
		setBounds(800,100,500,500);
		setVisible(true);
		setResizable(false);//창크기 고정
		
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		
		addKeyListener(this);
		
		//스레드생성
		Thread t = new Thread(this);
		t.start();
	}
	
	@Override
	public void paint(Graphics g) {
		//오른쪽
		g.drawImage(img, 
				x, y, x+50, y+50, //화면위치
				sel*50, 0, sel*50+50, 50,    //이미지위치
				this);
		//food 이미지 출력
		for(int i =0; i<foodX.length;i++) {
			g.drawImage(foodImg, foodX[i],foodY[i], this);
		}
		//food이미지의 좌표x,y를 미리 만든 난수로 설정을 하고 배열을 돌린다.
		//그럼 5개 생성
		//먹은거 처럼 보이게 할려면 지나갔을떄 범위좌표를 -로해서 이동을하면된다. 지우는건 번거롭
	}
	
//Runnable 스레드 ---------------------------------
		@Override
		public void run() {
			while(true) {
				if(sel%2 == 0)sel++;
				else sel --;
				
				x += mx;
				y += my;
				if(x>500) x=0;
				else if(x<0) x=500;
				else if(y>500) y=0;
				else if(y<0) y=500;
				
				
				repaint();//이게 없으면 한번돌고나서 홀수다음 바뀌지 않기 때문
				try {
					Thread.sleep(100);//기본이 1/1000초
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				
				for(int i=0; i<foodX.length;i++) {
					//if(x) 이렇게 하면 이미지의 가운데부분이 아니라 모서리라서 먹이를 먹는 모습이 이상해진다.
					//그림의 가운데 부분으로 설정을 해야한다.
					if(x+25>=foodX[i] && y+25>=foodY[i] && 
							x+25<=foodX[i]+20 && y+25<=foodY[i]+20) {
						foodX[i] = foodY[i] =-100;
					}
				}
				
			}//while
		}
//KeyListener----------------------------------------
	@Override
	public void keyPressed(KeyEvent k) {
		if(k.getKeyCode() == KeyEvent.VK_ESCAPE) {
			System.exit(0);
		}else if(k.getKeyCode() == KeyEvent.VK_LEFT) {
			sel = 0;
			mx = -10; my =0;
		}else if(k.getKeyCode() == KeyEvent.VK_RIGHT) {
			sel = 2;
			mx = +10; my =0;
		}else if(k.getKeyCode() == KeyEvent.VK_UP) {
			sel = 4;	
			mx =0; my = -10;
		}else if(k.getKeyCode() == KeyEvent.VK_DOWN) {
			sel = 6;
			mx =0; my = +10;
		}else if(k.getKeyCode() == KeyEvent.VK_SPACE) {
			sel = 2;
			x=225;
			y=225;
		}
		//repaint();
	}
	@Override
	public void keyReleased(KeyEvent k) {	}
	@Override
	public void keyTyped(KeyEvent k) {	}
	

//----------------------------------------------------------
	public static void main(String[] args) {
		Packman p = new Packman();
				
	}


}

728x90

'JAVA' 카테고리의 다른 글

스레드  (0) 2020.10.16
10/15 수업내용(타이머,  (0) 2020.10.15
10/14 수업  (0) 2020.10.14
미완성[메소드]정렬 sort(), Comparable vs Comparator  (0) 2020.10.14
10/13수업  (0) 2020.10.13
728x90

 

class AA{
public void sub() { }
}
class BB extands AA {
public void sub() throws Exception{ }
}
오버라이드된 메소드에는 throws를 하면 안된다.
그럼 부모의 메소드까지 전부다 throws해야하기 때문이다.


Component(도구)
ex)연필
   Button, TextField, Panel,...


Container
ex)필통
    Frame, Dialog
근데 Conainer에도 크고작은게 있어서 Dialog안에 Frame을 담을 수 있다.

 


예외처리

 

만약 사자를 없애면

이런 오류가 나온다. 1번방에 데이터가 없다는 오류다.

try~ catch

앞서 arg[0]값에 argument로 호러랑이를 저장했고 args를 num1에 저장했다.

num1은 String이고 우리가 입력한건 int이기 때문에 /를 하면 타입이 달라 오류가 나온다.

근데 이런 식으로 실행부에 try로 잡고 catch로 오류 메세지를 출력하는 Number~~~어쩌고 를 통해 
try에서 오류를 감지하면 catch부분에서 빨간 오류메세지가 아닌 우리가 입력한 메세지를 출력할 수 있다.

이렇게 메시지를 출력한다.

근데 수학적인 오류는 위의 방법으로는 오류가 나온다


그리고 이 상태에서 Argument에 호러랑이대신 25를 넣고 Sc를 통해 입력값에 0을 넣으면 

0/25가 되어 연산오류가 난다.

cathch를 하나 더 잡아주고 Ari~~를 이용하면

빨간 메세지가 아닌 우리가 정한 오류메세지를 출력할 수 있다.

근데 이거 안해도

에(double)로 형변환 넣어주면 오류안나고 계산한다.

DB처리할 때 사용하는 finally라는게 있다

작동 순서는 이렇고

이렇게 선언해주면

이렇게 결과를 도출한다.

지금까지의 Argument상태

이 부분을 문자로 바꾸고 실행해도 finally덕분에 오류가 안난다.

 

ㅇㅇㅇㅇㅇㅇㅇ

먼저 구구단을 만든다

bufferedReader부분의 예외처리가 전에 배운거랑 쪼금 다르니 읽어보기

try에서 에러를 감지하면
catch 코드가 강제로 빨간 글씨로 오류를 출력한다
throw new Exception()은 강제로 오류를 일으키는 메소드다.

e.printStackTrace(); 코드 가 오류를 추적해서 출력한다.

 
 

 


 

예외처리2

클래스를 만들고

앞서만든 클래스에 저렇게 넣어주면

오류가 좀 다르게 나온다.

그리고

저 부분을 사용하면

오류부분에 오류나는 클래스명까지 나온다.

 


 

Thread

작동 순서

스레드 상속받고 new로 스레드 3개 생성
근데 run은 우리가 하는게 아니라 운영체재가 한다.


결과
결과부분에서 [Thread-0, -1, -2]는 스레드의 이름이다
스레드에 우리가 직접 이름을 입력할 수 있다.

스레드에 이름넣기

스레드가 몇번째 인지 알아보기

스레드를 멈추는, 죽이는 방법도 있다


join()을 넣는건데 오류가 나기 떄문에 try, catch로 잡아보자
 우선순위를 줄 수도 있는데 정확하지가 않은것 같다



 



시계만들기

먼저 창을 만든다

paint()메소드를 이용해 시간을 출력한다. 두가지 방법이 있다.


폰트도 변경해주자. 
지금 상태는 한번 찍히고 갱신이 되지 않고 있다.
이제 시간이 계속 바뀌게 만들어보자
이제 시계부분으로 돌아가서 시간을 계속 갱신한다고 while문을 사용하면 시간이 바뀌긴 하는데
cpu가 그 while부분에 빠져있어서 닫는버튼이 안먹힌다.

한번에 여러 동작을 못하는 것이다. 이때 스레드가 필요

우선 implement를 하자. runnable이 스레드

다음 오버라이드 ㄱㄱ

스레드 생성, 시작

이렇게 paint()에 while을 지우고 run에 paint를 다시 부르는 repaint를 작성한다.
이렇게하면 시계가 나오는데 너무 빨라서 시간이 안보인다.

이렇게 고쳐주면 반복시간이 1000 =1초가 되어 이제 시간이보인다
아까는 1초도 아닌 0.0몇초로 바뀌는 거였다

 

 


 

 
 
 
728x90

+ Recent posts