본문 바로가기
코리아 IT아카데미/Java

16일차 | thread 동기화 , gif 넣기, 로또 번호 생성기

by Sharon kim 2021. 11. 8.

동작하는 GUI 구현하기

switch case, thread, while boolean 변수 = true;

 

package ch03;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

class MiniAmongUs extends JFrame implements ActionListener{

	BufferedImage backgroundImage;
	BufferedImage amongimage1;
	BufferedImage amongimage2;
	CustomJPanel customJPanel;
	
	//
	BorderLayout borderLayout;
	JPanel bottomPanel;
	JButton btnstart;
	JButton btnstop;
	boolean isOn = true;
	
	//thread 사용할 이미지
	int among1XPoint = 0;
	int among1YPoint = 370;
	
	int among2XPoint = 200;
	int among2YPoint = 200;
	
	public MiniAmongUs() {
		initData();
		setInitLayout();
		addEventListener();
	//스레드 동작
		Thread thread = new Thread(customJPanel);
		thread.start();
		addEventListener();
		
	}
	private void initData() {
		setTitle("어몽어스");
		setSize(600, 600);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		try {
			backgroundImage = ImageIO.read(new File("background1.jpg"));
			amongimage1 = ImageIO.read(new File("among1.png"));
			amongimage2 = ImageIO.read(new File("among2.png"));
		} catch (IOException e) {
			System.out.println("파일이 없습니다.");
		}
		
		customJPanel = new CustomJPanel();
		borderLayout = new BorderLayout();
		bottomPanel = new JPanel();
		btnstart = new JButton("start");
		btnstop = new JButton("stop");	
	}
	private void setInitLayout() {
		this.setVisible(true);
		this.setResizable(false);//이미지 늘어나지 않게
		this.setLayout(borderLayout);
		
		this.add(customJPanel, BorderLayout.CENTER);
		this.add(bottomPanel, BorderLayout.SOUTH);
		bottomPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
		bottomPanel.add(btnstart);
		bottomPanel.add(btnstop);
	}
	private void addEventListener() {
		
		btnstart.addActionListener(this);
		btnstop.addActionListener(this);
		
		this.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				int code = e.getKeyCode();
				System.out.println(code);
				switch (code) {
				case KeyEvent.VK_UP:
					among2YPoint -= 10;
					break;
				case KeyEvent.VK_DOWN:
					among2YPoint += 10;
					break;
				case KeyEvent.VK_LEFT:
					among2XPoint -= 10;
					break;
				case KeyEvent.VK_RIGHT:
					among2XPoint += 10;
					break;
				default:
					break;
				}
				repaint();
			}
		});
	}
	//내부 클래스 생성
	private class CustomJPanel extends JPanel implements Runnable{

		@Override
		protected void paintComponent(Graphics g) {
			super.paintComponent(g);
			g.drawImage(backgroundImage, 0, 0, 600, 600, null);
			g.drawImage(amongimage1, among1XPoint, among1YPoint, 100, 100, null);
			g.drawImage(amongimage2, among2XPoint, among2YPoint, 100, 100, null);
		}

		@Override
		public void run() {
			// 2. 변수를 새롭게 활용해서 while문을 멈추거나 다시 시작
			//할 수 있게 코드를 수정합니다.
			boolean isRight = true;
			while(true) {
				if(isOn) {
				if(isRight) {
					among1XPoint += 10;
				}else {
					among1XPoint -= 10;
				}
				if(among1XPoint == 400) {
					isRight = false;
				}
				if(among1XPoint == 0) {
					isRight = true;
				}
				//이미지 1과 이미지 2와 좌표값이 x, y일치한다면
				//이미지 2 없애라
				if((among1XPoint == among2XPoint)&&(among1YPoint == among2YPoint)) {
					amongimage2 = null;
				}
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
				repaint();
		}
			
	}
}
	@Override
	public void actionPerformed(ActionEvent e) {

		//1. 버튼이 start, stop 인지 구분해주세요
		JButton button = (JButton)e.getSource();
		if(button == btnstart) {
			System.out.println("시작버튼");
			isOn = true;
		}else {
			System.out.println("종료버튼");
			isOn = false;
		}
	}
}

public class MainTest1 {

	public static void main(String[] args) {
		new MiniAmongUs();
	}
}

어몽1(pink)은 thread로 좌우 반복 이동, 버튼으로 제어, 어몽2(gray)는 방향키로 이동가능, 둘이 만나면 어몽2는 사라짐.


gif 이미지 넣기

package ch03;

import java.awt.Container;
import java.awt.FlowLayout;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

class MyFrame1 extends JFrame{
	
    public MyFrame1(){
    
    setTitle("gif사용해보기");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container c = getContentPane();
    c.setLayout(new FlowLayout());

	JLabel textLabel = new JLabel("지구입니다.");
    ImageIcon img = new ImageIcon("image.gif");
    JLabel imageLabel = new JLabel(img);

    JLabel bottomTextLabel = new JLabel("지구는 오늘도 돈다");

    c.add(textLabel);
    c.add(imageLabel);
    c.add(bottomTextLabel);

	setSize(300 , 500);
	setVisible(true);
    
	}
}

public class MainTest2 {

	public static void main(String[] args) {
		new MyFrame1();
		
	}
}

thread 동기화 예제

package ch04;

class BankAccount {

	private int money = 100_000;

	// getter
	public int getMoney() {
		return this.money;
	}

	// setter
	public void setMoney(int money) {
		if (money <= 0) {
			System.out.println("잘못된 입력입니다.");
		} else {
			this.money = money;
		}
	}

	// 입금기능
	public synchronized void saveMoney(int money) {
		// 10만원 상태
		int currentMoney = getMoney();
		System.out.println("메서드 동작 확인 1 : saveMoney");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		setMoney(currentMoney + money);
		System.out.println("입금 후 계좌 잔액 : " + getMoney());
	}

	// 출금기능
	public void withdrawMoney(int money) {

		synchronized (this) {
			int currentMoney = getMoney();
			System.out.println("메서드 동작 확인 2 : withdrawMoney");
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			// 방어적 코드
			// Todo
			// 현재 금액보다 출금하려는 금액이 크면 출금이 안되게 변경

			setMoney(currentMoney - money);
			System.out.println("출금 후 계좌 잔액 : " + getMoney());
		}
	}
} // end of BankAccount class

class Father extends Thread {

	BankAccount account;

	public Father(BankAccount account) {
		this.account = account;
	}

	@Override
	public void run() {
		// 입금하기
		account.saveMoney(10_000);
	}
}

class Mother extends Thread {

	BankAccount account;

	public Mother(BankAccount account) {
		this.account = account;
	}

	@Override
	public void run() {
		// 출금하기
		account.withdrawMoney(5_000);
	}
}

public class SharedResource {

	public static void main(String[] args) {

		// 현재 10만원이 저금되어 있는 상태로 객체 생성
		BankAccount account = new BankAccount();

		Father father = new Father(account);
		Mother mother = new Mother(account);

		// 아버지가 입금하는 동작
		father.start();
		// 어머니가 출금하는 동작
		mother.start();

		// 정상처리금액 : 10만원 + 1만원 - 5천원 = 10만 5천원
		// 결과값 : 110000 ?? <--의도치 않은 결과를 만날 수 있다.

		// 동기화
		// 임계 영역이 발생될 때는 (작업자간 자원을 공유하는 상태)
		// 현재 자원(데이터) 사용하고 있기 때문에 보호 처리를 해주어야 한다.
		// 다른 작업자가 사용하지 못하도록 lock 을 걸어준다.
		// 순서를 지켜서 작업을 하게 함
		// 하는 방법 - 
		//1. synchronized 메서드
		//2. synchronized {블록}
	}
}

로또 번호 생성하기

package ch05;


import java.util.Arrays;
import java.util.Random;

public class LottoNumber {

	static final int LOTTO_NUM_SIZE = 6; 
	
	// 로또 번호를 생성하는 기능 (6자리)
	
	public int[] getLottoNumber() {
		// 번호를 담을 공간 만들기 
		int[] numbers = new int[LOTTO_NUM_SIZE];
		
		Random  random = new Random(); 
		// [1 ~ 45]
		for (int i = 0; i < numbers.length; i++) {
			numbers[i] = random.nextInt(45) + 1;
			
			for (int j = 0; j < i; j++) {
				if(numbers[i] == numbers[j]) {
					i = i - 1; 
					break; 
				}
			}
		}
		// 배열 정렬 
		Arrays.sort(numbers); 
		return numbers; 
	}
	
	// 테스트 코드 
	public static void main(String[] args) {
		LottoNumber lottoNumber = new LottoNumber();
		int[] nums = lottoNumber.getLottoNumber(); 
		for (int i : nums) {
			System.out.print(i + "\t");
		}
	}
	
}

로또 번호 생성하는 GUI 만들기

package ch05;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class LottoFrame extends JFrame implements ActionListener {

	JButton button; 
	LottoPanel lottoPanel;
	LottoNumber lottoNumber; 
	int[] lotto = new int[LottoNumber.LOTTO_NUM_SIZE];
	
	public LottoFrame() {
		initData();
		setInitLayout();
		addEventListener();
	}
	
	private void initData() {
		setTitle("로또번호생성기");
		setSize(600, 400);
		button = new JButton("++ 로또번호 생성하기 ++");
		lottoPanel = new LottoPanel();
		lottoNumber = new LottoNumber(); 
	}
	
	private void setInitLayout() {
		setVisible(true);
		setBackground(Color.gray);
		add(button, BorderLayout.NORTH);
		add(lottoPanel, BorderLayout.CENTER);
		
	}
	
	private void addEventListener() {
		button.addActionListener(this);
	}
	
	
	@Override
	public void actionPerformed(ActionEvent e) {
		// 6자리 랜덤 숫자가 배열로 넘어 온다. 
		lotto = lottoNumber.getLottoNumber(); 
		repaint();
	}
	
	class LottoPanel extends JPanel {
		
		@Override
		public void paint(Graphics g) {
			Font font = new Font("나눔고딕", Font.BOLD, 20);
			g.setFont(font);
			
			if(lotto[0] == 0) {
				g.drawString("로또 버튼을 클릭하세요", 180, 180);
				return; 
			}
			
			int xPoint = 150; 
			for(int i = 0; i < lotto.length; i++) {
				g.drawString(lotto[i] + "", xPoint , 150);
				xPoint += 50; 
			}
			
		}
	}
	
	
	public static void main(String[] args) {
		new LottoFrame();
	}
	
}