본문 바로가기
Programming/Java

Java soket,dialog,button을 활용한 채팅창 만들기

by wonduk 2023. 7. 17.
728x90

채팅 서버를 만들기 위해서는 서버측과 클라이언트 측 을 만들어 줘야하는데 두개의 코딩은 다음과 같습니다.

 

서버코드

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;

public class ChatServer extends JFrame implements ActionListener {
	private BufferedReader in = null;
	private BufferedWriter out = null;
	private ServerSocket listener = null;
	private Socket socket = null;
	private Receiver receiver; // JTextArea를 상속받고 Runnable 인터페이스를 구현한 클래스로서 받은 정보를 담는 객체
	private JTextField sender; // JTextField 객체로서 보내는 정보를 담는 객체
	private MyDialog dialog;
	private JTextField tf = new JTextField(10);
	public JButton nameBtn = new JButton("이름변경");
	private boolean valid = false;
	public String mynameText;
	public String clnameText;

	
	public ChatServer() {
		setTitle("서버 채팅 창"); // 프레임 타이틀
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //프레임 종료 버튼(X)을 클릭하면 프로그램 종료
		Container c = getContentPane();
		
		c.setLayout(new BorderLayout()); //BorderLayout 배치관리자의 사용
		receiver = new Receiver(); // 클라이언트에서 받은 메시지를 출력할 컴퍼넌트
		receiver.setEditable(false); // 편집 불가

		sender = new JTextField();
		sender.addActionListener(this);
		
		nameBtn.setBounds(400, 0, 100, 50);
		add(nameBtn);
		nameBtn.setVisible(true);
		dialog = new MyDialog(this,"Test Dialog",true);
		nameBtn.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
//				dialog.setVisible(true);
				do {
				    try {
				        mynameText = String.valueOf(JOptionPane.showInputDialog("변경할 이름을 적으세요"));
				        valid = true;
				    } catch (NumberFormatException e3) {}
				} while(!valid);
			}
		});
		
		add(new JScrollPane(receiver),BorderLayout.CENTER); // 스크롤바를 위해  ScrollPane 이용
		add(sender,BorderLayout.SOUTH);
		
		setSize(500, 500); // 폭 400 픽셀, 높이 200 픽셀의 크기로 프레임 크기 설정
		setVisible(true); // 프레임이 화면에 나타나도록 설정
		
		try {
			setupConnection();
		} catch (IOException e) {
			handleError(e.getMessage());
		}
		
		Thread th = new Thread(receiver); // 상대로부터 메시지 수신을 위한 스레드 생성
		th.start();
	}
	private void setupConnection() throws IOException {
		listener = new ServerSocket(9999); // 서버 소켓 생성
		socket = listener.accept(); // 클라이언트로부터 연결 요청 대기
		//System.out.println("연결됨");
		receiver.append("클라이언트로부터 연결 완료");
		int pos = receiver.getText().length();
		receiver.setCaretPosition(pos); // caret 포지션을 가장 마지막으로 이동
		
		in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 클라이언트로부터의 입력 스트림
		out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); // 클라이언트로의 출력 스트림
	}

	private static void handleError(String string) {
		System.out.println(string);
		System.exit(1);
	}
	
	private class Receiver extends JTextArea implements Runnable {
		@Override
		public void run() {
			String msg = null;
			while (true) {
				try {
					msg = in.readLine(); // 상대로부터 한 행의 문자열 받기
				} catch (IOException e) {
					handleError(e.getMessage());
				} 
				this.append("\n " + msg); // 받은 문자열을 JTextArea에 출력
				int pos = this.getText().length();
				this.setCaretPosition(pos); // caret 포지션을 가장 마지막으로 이동
			}
		}
	}

	@Override
	public void actionPerformed(ActionEvent e) { // JTextField에 <Enter> 키 처리
		if (e.getSource() == sender) {
			String msg = sender.getText(); // 텍스트 필드에서 문자열 얻어옴
			try {
				out.write(mynameText+" : "+msg+"\n"); // 문자열 전송
				out.flush();
				
				receiver.append("\n" +mynameText+" : "+ msg);// JTextArea에 출력
				int pos = receiver.getText().length();
				receiver.setCaretPosition(pos); // caret 포지션을 가장 마지막으로 이동
				sender.setText(null); // 입력창의 문자열 지움
			} catch (IOException e1) {
				handleError(e1.getMessage());
			} 
		}
	}
	
	class MyDialog extends JDialog{
		
		public MyDialog(JFrame frame, String title, boolean modal) {
			super(frame,title,modal);
			setLayout(new FlowLayout());
			add(tf);
			setSize(20,100);
		}
	}

	public class DialogEx extends JFrame{
		public DialogEx(){
			super("DialogEx 예제프레임");
			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			JButton btn = new JButton("show Dialog");
			
			dialog = new MyDialog(this,"Test Dialog",true);
			btn.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent e) {
					dialog.setVisible(true);
				}
			});
			getContentPane().add(btn);//컨테이너를 꼭 구할 필요는 없음 그냥 add만써도 가능 컨테이너를 안 구하면 프레임 자체에 배경색을 넣을 수 없음, 그래서 보통 패널을 올린다음에 패널에 색을 많이 칠함
			setSize(400,200);
			setVisible(true);
		}
	}
	
	public static void main(String[] args) {
		new ChatServer();
	}

}

클라이언트 코드 

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ChatClient extends JFrame implements ActionListener {
	private BufferedReader in = null;
	private BufferedWriter out = null;
	private Socket socket = null;
	private Receiver receiver = null; // JTextArea를 상속받고 Runnable 인터페이스를 구현한 클래스로서 받은 정보를 담는 객체
	private JTextField sender = null; // JTextField 객체로서 보내는 정보를 담는 객체
	private MyDialog dialog;
	private JTextField tf = new JTextField(10);
	private JButton nameBtn2 = new JButton("이름변경");
	private boolean valid = false;
	public String clnameText;
	public String mynameText;
	
	public ChatClient() {
		setTitle("클라이언트 채팅 창"); // 프레임 타이틀
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //프레임 종료 버튼(X)을 클릭하면 프로그램 종료
		Container c = getContentPane();
		
		c.setLayout(new BorderLayout()); //BorderLayout 배치관리자의 사용
		receiver = new Receiver(); // 서버에서 받은 메시지를 출력할 컴퍼넌트
		receiver.setEditable(false); // 편집 불가
		
		sender = new JTextField();
		sender.addActionListener(this);
		
		nameBtn2.setBounds(400, 0, 100, 50);
		add(nameBtn2);
		nameBtn2.setVisible(true);
		dialog = new MyDialog(this,"Test Dialog",true);
		nameBtn2.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				do {
				    try {
				        clnameText = String.valueOf(JOptionPane.showInputDialog("변경할 이름을 적으세요"));
				        valid = true;
				    } catch (NumberFormatException e3) {}
				} while(!valid);
			}
		});
		
		c.add(new JScrollPane(receiver),BorderLayout.CENTER); // 스크롤바를 위해  ScrollPane 이용
		c.add(sender,BorderLayout.SOUTH);
		
		setSize(500, 500); // 폭 400 픽셀, 높이 200 픽셀의 크기로 프레임 크기 설정
		setVisible(true); // 프레임이 화면에 나타나도록 설정
		
		
		try {
			setupConnection();
		} catch (IOException e) {
			handleError(e.getMessage());
		}
		
		Thread th = new Thread(receiver); // 상대로부터 메시지 수신을 위한 스레드 생성
		th.start();
	}
	private void setupConnection() throws IOException {
		socket = new Socket("localhost", 9999); // 클라이언트 소켓 생성
		// System.out.println("연결됨");
		receiver.append("서버에 연결 완료");
		int pos = receiver.getText().length();
		receiver.setCaretPosition(pos); // caret 포지션을 가장 마지막으로 이동
		
		in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 클라이언트로부터의 입력 스트림
		out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); // 클라이언트로의 출력 스트림
	}


	private static void handleError(String string) {
		System.out.println(string);
		System.exit(1);
	}
	
	private class Receiver extends JTextArea implements Runnable {
		@Override
		public void run() {
			String msg = null;
			while (true) {
				try {
					msg = in.readLine(); // 상대로부터 한 행의 문자열 받기
				} catch (IOException e) {
					handleError(e.getMessage());
				} 
				this.append("\n " + msg); // 받은 문자열을 JTextArea에 출력
				int pos = this.getText().length();
				this.setCaretPosition(pos); // caret(커서)을 가장 마지막으로 이동
			}
		}
	}
	
	@Override
	public void actionPerformed(ActionEvent e) { // JTextField에 <Enter> 키 처리
		if (e.getSource() == sender) {
			String msg = sender.getText(); // 텍스트 필드에 사용자가 입력한 문자열
			try {
				out.write(clnameText+" : "+msg+"\n"); // 문자열 전송
				out.flush();
				
				receiver.append("\n "+clnameText+" : "+ msg); // JTextArea에 출력
				int pos = receiver.getText().length();
				receiver.setCaretPosition(pos); // caret 포지션을 가장 마지막으로 이동
				sender.setText(null); // 입력창의 문자열 지움
			} catch (IOException e1) {
				handleError(e1.getMessage());
			} 
		}
	}
	
	class MyDialog extends JDialog{
		
		public MyDialog(JFrame frame, String title, boolean modal) {
			super(frame,title,modal);
			setLayout(new FlowLayout());
			add(tf);
			setSize(20,100);
		}
	}

	public class DialogEx extends JFrame{
		public DialogEx(){
			super("DialogEx 예제프레임");
			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			JButton btn = new JButton("show Dialog");
			
			dialog = new MyDialog(this,"Test Dialog",true);
			btn.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent e) {
					dialog.setVisible(true);
				}
			});
			getContentPane().add(btn);//컨테이너를 꼭 구할 필요는 없음 그냥 add만써도 가능 컨테이너를 안 구하면 프레임 자체에 배경색을 넣을 수 없음, 그래서 보통 패널을 올린다음에 패널에 색을 많이 칠함
			setSize(400,200);
			setVisible(true);
		}
	}
	
	
	public static void main(String[] args) {
		new ChatClient();
	}
}

위의 코드 중 다이어로그를 생성하는 코드들은 다음과 같습니다.

클라이언트 코드와 서버측 코드와 동일 합니다.

	private MyDialog dialog;
	private JTextField tf = new JTextField(10);
	private JButton nameBtn2 = new JButton("이름변경");
	private boolean valid = false;
	public String clnameText;
	public String mynameText;
   
   
   
   //ChatClient() 클래스 
    nameBtn2.setBounds(400, 0, 100, 50);
		add(nameBtn2);
		nameBtn2.setVisible(true);
		dialog = new MyDialog(this,"Test Dialog",true);
		nameBtn2.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				do {
				    try {
				        clnameText = String.valueOf(JOptionPane.showInputDialog("변경할 이름을 적으세요"));
				        valid = true;
				    } catch (NumberFormatException e3) {}
				} while(!valid);
			}
		});
        
        
        
        
        
        //다이어로그를 만드는 클래스들
        class MyDialog extends JDialog{
		
		public MyDialog(JFrame frame, String title, boolean modal) {
			super(frame,title,modal);
			setLayout(new FlowLayout());
			add(tf);
			setSize(20,100);
		}
	}

	public class DialogEx extends JFrame{
		public DialogEx(){
			super("DialogEx 예제프레임");
			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			JButton btn = new JButton("show Dialog");
			
			dialog = new MyDialog(this,"Test Dialog",true);
			btn.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent e) {
					dialog.setVisible(true);
				}
			});
			getContentPane().add(btn);//컨테이너를 꼭 구할 필요는 없음 그냥 add만써도 가능 컨테이너를 안 구하면 프레임 자체에 배경색을 넣을 수 없음, 그래서 보통 패널을 올린다음에 패널에 색을 많이 칠함
			setSize(400,200);
			setVisible(true);
		}
	}
728x90