codingeverybody / codingyahac

https://coding.yah.ac
292 stars 50 forks source link

자바를 이용한 채팅프로그램을 만드는 중 궁금한 부분 #653

Open CEmmanuelP opened 5 years ago

CEmmanuelP commented 5 years ago

해결하고자 하는 문제

MainScreen, MultiClient, MultiClientThread, MultiServer, MultiServerThread로 되어 있습니다. MainScreen에서 chat버튼을 누르면 MultiClient로 만든 GUI가 나오면서 채팅이 시작되게 하고 싶습니다.

  1. 지금은 Client에 직접 id(nickname)과 ip를 명령행 인자로 받아서 MultiClient를 실행시키고 있는데 어떻게 하면 MainScreen에서 chat버튼을 누르면 MainScreen에서 설정했던 값들을 적용시켜서 MultiClient를 실행시킬 수 있을까요 ㅠ 방법을 모르겠습니다

    코드 혹은 오류

    
    MainScreen.java

package chatprogram;

import javax.swing.; import java.awt.; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;

class Screen extends JFrame implements ActionListener, ItemListener, Runnable{ public JLabel jl1, jl2, jl3, jl4, jl5; static JTextField jtf; private JComboBox jcb1; private JButton jb1, jb2, jb3;

static Color color1;
static Font f1;

String[] font = {"글꼴을 고르세요", "굴림", "궁서", "바탕", "돋움", "맑은 고딕"};

JPanel jp1 = new JPanel();

public Screen(){
    jtf = new JTextField("닉네임 입력");
    jl1 = new JLabel("Multi Chat");
    jl2 = new JLabel("Nickname : ");
    jl3 = new JLabel("Font");
    jl4 = new JLabel("Color");
    jl5 = new JLabel(jtf.getText());
    jl5.setFont(new Font("굴림", Font.BOLD, 25));
    jcb1 = new JComboBox(font);
    jcb1.addItemListener(this);
    jb1 = new JButton("색을 골라주세요");
    jb2 = new JButton("chat");
    jb3 = new JButton("memo");

    jb1.addActionListener(this);
    jb2.addActionListener(this);
    jb3.addActionListener(this);

    jl1.setSize(330, 70);
    jl1.setLocation(100, 30);
    jl1.setFont(new Font("버다나", Font.BOLD, 30));

    jl2.setSize(120, 30);
    jl2.setLocation(30, 180);
    jl2.setFont(new Font("본고딕", Font.BOLD, 19));

    jl3.setSize(120, 30);
    jl3.setLocation(30, 250);
    jl3.setFont(new Font("본고딕", Font.BOLD, 19));

    jl4.setSize(120, 30);
    jl4.setLocation(100, 30);
    jl4.setFont(new Font("본고딕", Font.BOLD, 1));

    jtf.setSize(154, 40);
    jtf.setLocation(150, 175);
    jtf.setFont(new Font("굴림", Font.BOLD, 15));

    jcb1.setSize(150, 40);
    jcb1.setLocation(150,245);
    jcb1.setFont(new Font("본고딕", Font.BOLD, 15));

    jb1.setSize(150, 40);
    jb1.setLocation(150,245);
    jb1.setFont(new Font("본고딕", Font.BOLD, 15));

    jb2.setSize(160, 40);
    jb2.setLocation(10,515);
    jb2.setFont(new Font("본고딕", Font.BOLD, 15));

    jb3.setSize(160, 40);
    jb3.setLocation(175,515);
    jb3.setFont(new Font("본고딕", Font.BOLD, 15));

    this.add(jl1);
    this.add(jl2);
    this.add(jl3);
    this.add(jl4);
    this.add(jtf);
    this.add(jcb1);
    this.add(jb1);
    this.add(jb2);
    this.add(jb3);

    setLayout(null);
    setSize(360, 600);
    setVisible(true);

    jp1.setSize(340, 60);
    jp1.setLocation(0, 420);
    jp1.setVisible(true);
    this.add(jp1,"panel1");
    jp1.setLayout(new FlowLayout());
    jp1.add(jl5);
}

public void actionPerformed(ActionEvent e){
    if(e.getSource() == jb1){
        color1 = JColorChooser.showDialog(null, "나를 표현할 색을 골라보세요.", Color.CYAN);
        if(color1 != null){
            jl5.setForeground(color1);
        }
    }
    if(e.getSource() == jb2){
        //채팅방 입장
        //여기서 설정한 nickname, Font, Color받아서 적용
        //ip, port도 받아야 client 호출
    }
    if(e.getSource() == jb3){
        Picture22 p = new Picture22();
    }
}

public void itemStateChanged(ItemEvent e){
    if(e.getItem().equals("궁서")){
        jl5.setFont(new Font("궁서", Font.BOLD, 25));
        f1 = new Font("궁서", Font.BOLD, 25);
    };

    if(e.getItem().equals("바탕")){
        jl5.setFont(new Font("바탕", Font.BOLD, 25));
        f1 = new Font("바탕", Font.BOLD, 25);
    };

    if(e.getItem().equals("굴림")){
        jl5.setFont(new Font("굴림", Font.BOLD, 25));
        f1 = new Font("굴림", Font.BOLD, 25);
    };

    if(e.getItem().equals("돋움")){
        jl5.setFont(new Font("돋움", Font.BOLD, 25));
        f1 = new Font("돋움", Font.BOLD, 25);
    };
    if(e.getItem().equals("맑은 고딕")){
        jl5.setFont(new Font("맑은 고딕", Font.BOLD, 25));
        f1 = new Font("맑은 고딕", Font.BOLD, 25);
    };

}

public void run(){
    while(jl5 != null){
        jl5.setText(jtf.getText());

        if(jl5 != null){
            String nick = jl5.getText();
            char[] name = new char[10];
            name = nick.toCharArray();

            if(name.length > 7){
                JOptionPane.showMessageDialog(jtf, "닉네임은 8글자 이하로 설정 가능합니다");
                jtf.setText("닉네임 입력");
            }
        }
    }
}

}

class Picture22 extends JFrame implements ActionListener{ JTextArea jta; JButton jb1; String memo = "";

public Picture22(){
    try{
        FileInputStream fis1 = new FileInputStream("e:/data3.txt");
        int tmp = 0;
        while((tmp = fis1.available()) > 0){
            byte[] bae = new byte[tmp];
            int bada = fis1.read(bae);
            if(bada == -1) break;
            String str = new String(bae);
            memo += str;
        }
        fis1.close();
    }catch(IOException e){
        e.printStackTrace();
    }

    jb1 = new JButton("저장");
    jta = new JTextArea(memo, 300, 300);

    jb1.setSize(100, 50);
    jb1.setLocation(10, 10);
    jb1.setFont(new Font("굴림", Font.BOLD, 15));
    jb1.addActionListener(this);

    jta.setSize(300, 300);
    jta.setLocation(10, 100);
    jta.setVisible(true);

    this.add(jb1);
    this.add(jta);

    setLayout(null);
    setSize(700, 700);
    setVisible(true);
}

public void actionPerformed(ActionEvent e){
    if(e.getSource() == jb1){
        int data = 0;
        try{
            File file = new File("e:/eata3.txt");
            FileOutputStream fos1 = new FileOutputStream(file);
            byte[] bae = jta.getText().getBytes();
        }catch(IOException e1){
            e1.printStackTrace();
        }
    }
}

}

public class MainScreen { public static void main(String[] args){ Screen sc = new Screen(); } }

MultiServer.java

package chatprogram;

import java.io.; import java.net.; import java.util.*;

public class MultiServer { private ArrayList list; private Socket socket;

public MultiServer() throws IOException {

    list = new ArrayList<MultiServerThread>();//사용자 목록 객체
    ServerSocket serverSocket = new ServerSocket(5002);//서버(소켓) 생성
    MultiServerThread mst = null;

    boolean isStop = false;
    while (!isStop) {//true
        System.out.println("Server ready...");
        socket = serverSocket.accept();//서버 받음
        System.out.println("start");
        mst = new MultiServerThread(this);
        list.add(mst);
        Thread t = new Thread(mst);
        t.start();
    }
}

public ArrayList<MultiServerThread> getList() {
    return list;
}

public Socket getSocket() {
    return socket;
}

public static void main(String arg[]) throws IOException {
    new MultiServer();
}

}

MultiServerThread

package chatprogram;

import java.net.; import java.io.;

public class MultiServerThread implements Runnable { private Socket socket; private MultiServer ms; private ObjectInputStream ois; private DataOutputStream dos; private ObjectOutputStream oos; private int count = 0, count1 = 0; public MultiServerThread(MultiServer ms) { this.ms = ms;//서버 정보 받아옴 }

public synchronized void run() {
    boolean isStop = false;
    try {
        socket = ms.getSocket();
        ois = new ObjectInputStream(socket.getInputStream());
        oos = new ObjectOutputStream(socket.getOutputStream());//i/o stream 객체생성
        String message = null;
        while (!isStop) {
            message = (String) ois.readObject();
            String[] str = message.split("#");
            if (str[1].equals("exit")) {
                broadCasting(message);
                isStop = true;
            }else if(str[1].equals("voteY")){
                broadCasting("vote"+"#"+(count + 1)+"/" + ms.getList().size()+"투표완료"+"#"+"Y"+"#"+count+"#"+count1);//vote#1/5투표완료#Y#1#count1
            }else if(str[1].equals("voteN")){
                broadCasting("vote"+"#"+(count + 1)+"/" + ms.getList().size()+"투표완료"+"#"+"N"+"#"+count+"#"+count1);//vote#1/5투표완료#N#1#count1
            }else if(str[1].equals("count")){
                count = Integer.parseInt(str[1]);
                count1 = Integer.parseInt(str[2]);
            }else {
                broadCasting(message);
            }

            if(count >= ms.getList().size()) {
                if(ms.getList().size()/2+1 <= count1) {
                    broadCasting("voteresult"+"#"+"voteY");//voteresult#voteY
                }else {
                    broadCasting("voteresult"+"#"+"voteN");
                }
            }
        }

        ms.getList().remove(this);
        System.out.println(socket.getInetAddress() + "정상적으로 종료하셨습니다");
        System.out.println("list size : " + ms.getList().size());
    } catch (Exception e) {
        ms.getList().remove(this);
        System.out.println(socket.getInetAddress() + "비정상적으로 종료하셨습니다");
        System.out.println("list size : " + ms.getList().size());
    }
}

public void broadCasting(String message) throws IOException {//모두에게 뿌려주는
    for (MultiServerThread ct : ms.getList()) {
        ct.send(message);
    }
}

public void send(String message) throws IOException {//출력용
    oos.writeObject(message);
}

}

MultiClient

package chatprogram;

import java.awt.BorderLayout; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket;

import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.text.BadLocationException; import javax.swing.text.Document;

public class MultiClient implements ActionListener{ private Socket socket;//원통 private ObjectInputStream ois;//받는용 private ObjectOutputStream oos;//출력용 private JFrame jframe; private JTextField jtf; // private JTextArea jta; private JLabel jlb1, jlb2; private JPanel jp1, jp2; private String ip; private String id; private JButton jbtn; private JTextPane jtp; private JFrame votef; private JButton btagree, btdisagree;

//생성자 ? IP(연결하려는 서버IP) 와 ID를 인자로 받는다.

public MultiClient(String argIp, String argId){
    ip = argIp;
    id = argId;

    jframe = new JFrame("Multi Chatting");
    jtf = new JTextField(30);             //JTextField는 한줄짜리 입력창
    // jta = new JTextArea("", 10, 50);   //JTextArea는 여러줄짜리 입력창
    jtp = new JTextPane();
    jtp.setPreferredSize(new Dimension(100, 500));
    jlb1 = new JLabel("Usage ID : [[ " + id + " ]]");
    jlb2 = new JLabel("IP : "+ ip);
    jbtn = new JButton("종료");
    //jbtn2 = new JButton("사용자 목록");
    jp1 = new JPanel();
    jp2 = new JPanel();
    jlb1.setBackground(Color.yellow);
    jlb2.setBackground(Color.green);
    jtp.setBackground(Color.pink);
    //jta.setBackground(Color.pink);
    jp1.setLayout(new BorderLayout());
    jp2.setLayout(new BorderLayout());
    jp1.add(jbtn, BorderLayout.EAST);
    //jp1.add(jbtn2, BorderLayout.WEST);
    jp1.add(jtf, BorderLayout.CENTER);
    jp2.add(jlb1, BorderLayout.CENTER);
    jp2.add(jlb2, BorderLayout.EAST);
    jframe.add(jp1, BorderLayout.SOUTH);
    jframe.add(jp2, BorderLayout.NORTH);

    JScrollPane jsp = new JScrollPane(jtp, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,  JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    jframe.add(jsp, BorderLayout.CENTER);

    jtf.addActionListener(this);     //JTextField에 ActionListener연결
    jbtn.addActionListener(this);  //JButton에 ActionListener 연결

//JFrame에 WindowListener를 연결하는데, WindowsAdapter 익명클래스를 생성하면서 필요한 메서드들(windowClosing(), windowOpened())을 오버라이딩 했다.

    jframe.addWindowListener(new WindowAdapter(){
        public void windowClosing(WindowEvent e){
            try{

//윈도우를 닫을 때 사용자가 종료 메세지를 보낸 것과 동일하게 문자열을 만들어 소켓에 기록한다. oos.writeObject(id+"#exit"); }catch(IOException ee){ ee.printStackTrace(); } System.exit(0); //어플리케이션 종료 } public void windowOpened(WindowEvent e){ //윈도우가 열리면 JTextField에 커서를 둔다. jtf.requestFocus();//키 이벤트를 받을 컴포넌트를 강제로 설정(창이열리면 글쓰는공간에 포커스맞춰짐) } }); //jta.setEditable(false); //JTextArea 를 읽기전용으로 jtp.setEditable(false); //JTextpane을 읽기전용으로 //스크린의 사이즈를 얻어오기 위해서 Toolkit 객체를 생성한다. Toolkit tk = Toolkit.getDefaultToolkit(); //Toolkit의 getScreenSize() 메서드를 사용해서 스크린사이즈를 담은 Dimension 객체를 리턴받는다. Dimension d = tk.getScreenSize(); int screenHeight = d.height; int screenWidth = d.width; jframe.pack(); //JFrame의 사이즈를 서브콤포넌트들에 맞게 자동으로 조정해준다. jframe.setLocation((screenWidth - jframe.getWidth())/2, (screenHeight - jframe.getHeight())/2); jframe.setResizable(false); jframe.setVisible(true);

    //jtp.setEditable(false);
}

//ActionListener 인터페이스가 강제하는 메서드
public void actionPerformed(ActionEvent e){

//ActionEvent의 getSource() 메서드는 이벤트를 발생시킨 객체 자체를 리턴시켜 준다. Object obj = e.getSource(); String msg = jtf.getText(); //JTextField에서 값을 읽어오는 getText() 메서드 //ActionListener에 연결한 객체가 두 개 이상이므로 IF문을 사용해 구분하였다. //JTextField의 요청일 경우 if(obj == jtf){ if(msg == null || msg.length()==0){ //메세지 내용이 없을 경우 //Alert창 : JOptionPane.showMessageDialog(소속되는 상위객체, 메세지객체, 메세지창제목, 메세지창종류) JOptionPane.showMessageDialog(jframe, "글을 쓰세요", "경고", JOptionPane.WARNING_MESSAGE); }else{ //메세지 내용이 있을 경우 try{ oos.writeObject(id+"#"+msg); //메세지를 직렬화 하여 소켓에 기록 //id#msg }catch(IOException ee){ ee.printStackTrace(); }

            jtf.setText("");   //기록한 후에는 입력창을 지우고 다시 입력받을 준비를 한다.
        }

//JButton의 요청일 경우 (종료버튼) }else if(obj == jbtn){ try{ oos.writeObject(id+"#exit"); //종료메세지 생성후 전송 }catch(IOException ee){ ee.printStackTrace(); } System.exit(0); //어플리케이션 종료 }/else if(obj == jbtn2) { System.out.println(); }/else if(obj == btagree){ System.out.println(btagree.getText()); try { oos.writeObject(id+"#"+"voteY");//id#voteY }catch(IOException e1) { e1.printStackTrace(); } votef.dispose(); }else if(obj == btdisagree) { System.out.println(btdisagree.getText()); try { oos.writeObject(id+"#"+"voteN");//id#voteN }catch(IOException e1) { e1.printStackTrace(); } } }

//걍 System.exit(0)를 줄인 메서드

public void exit(){
    System.exit(0);
}

//객체 생성과 동시에 실행시키고자 만든 메서드

public void init() throws IOException{
    socket = new Socket(ip, 5002);   //서버에 연결하는 소켓 객체 생성
    System.out.println("connected..");
    oos = new ObjectOutputStream(socket.getOutputStream());
    ois = new ObjectInputStream(socket.getInputStream());

//MultiClientThread 객체를 생성하면서 자신(MultiClient)을 인자로 넘긴다. MultiClientThread ct = new MultiClientThread(this); //MultiClientThread 스레드를 시작한다. Thread t = new Thread(ct); t.start(); }

public static void main(String[] args)throws IOException{
    //JFrame.setDefaultLookAndFeelDecorated(true);
    MultiClient cc = new MultiClient(args[0], args[1]);
    cc.init();
}

public ObjectInputStream getOis(){
    return ois;
}

public JTextPane getJtp() {
    return jtp;
}

public ObjectOutputStream getOos() {
    return oos;
}

/ public JTextArea getJta(){ return jta; } /

public String getId(){
    return id;
}

public void setId(String id) {
    this.id = id;
}

public void append(String s) {
    try {
        Document doc = jtp.getDocument();
        doc.insertString(doc.getLength(), s, null);
    }catch(BadLocationException exc) {
        exc.printStackTrace();
    }
}

public void vote() {
    votef = new JFrame("강퇴투표");
    votef.setBounds(900, 500, 130, 100);
    btagree = new JButton("찬성");
    btdisagree = new JButton("반대");
    votef.add(btagree, BorderLayout.WEST);
    votef.add(btdisagree, BorderLayout.EAST);
    votef.setVisible(true);
    btagree.addActionListener(this);
    btdisagree.addActionListener(this);

}

MultiClientThread.java

package chatprogram;

import java.io.IOException;

import chatprogram.MultiClient;

public class MultiClientThread extends Thread{ private MultiClient mc;

private int count = 0, count1 = 0;

public MultiClientThread(MultiClient mc) {
    this.mc = mc;
}

public void run() {
    String message = null;
    String[] receivedMsg = null;
    boolean isStop = false;

    boolean votecheck = false;

    String votename = null;
    String[] wmessage = null;

    while(!isStop) {
        try {
            message = (String)mc.getOis().readObject();
            receivedMsg = message.split("#");//eugene#/vote you
            wmessage = receivedMsg[1].split(" ");// /vote you
        }catch(Exception e) {
            e.printStackTrace();
            isStop = true;
        }

        System.out.println(receivedMsg[0] + " : " + receivedMsg[1]);//eugene : hi

        if(receivedMsg[1].equals("exit")) {
            if(receivedMsg[0].equals(mc.getId())) {
                mc.exit();
            }else {
                mc.append(receivedMsg[0] + "님이 종료하셨습니다." + System.getProperty("line.separator"));//줄바꿈(OS상관없이)
                mc.getJtp().setCaretPosition(mc.getJtp().getDocument().getLength());
            }
        }else if(receivedMsg[0].equals("vote")){//vote # 1/5 투표완료 # Y # count # count1
            if(receivedMsg[2].equals("Y")) {
                count1 = Integer.parseInt(receivedMsg[4]) + 1;//vote # 1/5 투표완료 # Y # 1 # count1++
            }else if(receivedMsg[2].equals("N")) {
                count1 = Integer.parseInt(receivedMsg[4]);//vote # 1/5 투표완료 # N # 1 # count1++
            }

            count = Integer.parseInt(receivedMsg[3]) + 1; //count++
            try {
                mc.getOos().writeObject("count#" + count + "#" + count1 );//count#2#1
            }catch(IOException e) {
                e.printStackTrace();
            }
            mc.append(receivedMsg[1] + System.getProperty("line.separateor"));

        }else if(receivedMsg[0].equals("voteresult")){//voteresult#voteY/N
            count = 0;
            if(receivedMsg[1].equals("voteY")) {
                if(votename.equals(mc.getId())) {
                    mc.exit();
                }else {
                    mc.append(votename+"님이 강퇴 당하였습니다" +System.getProperty("line.separator"));
                    mc.getJtp().setCaretPosition(mc.getJtp().getDocument().getLength());
                }
            }
        }else if(wmessage[0].equals("/vote")){
            mc.append(wmessage[1] + "님의 강퇴 투표가 시작되었습니다" + System.getProperty("line.separator"));
            votename = wmessage[1];
            votecheck = true;
        }else{
            mc.append(receivedMsg[0] + " : " + receivedMsg[1] + System.getProperty("line.separator"));
            mc.getJtp().setCaretPosition(mc.getJtp().getDocument().getLength());
        }//if - end

        if(votecheck) {
            mc.vote();
            votecheck = false;
        }
    }//while - end
}


# 환경
사용중인 운영체제, 언어, 라이브러리의 버전을 적어주세요.

intellij IDEA(Version 2019.1.3), eclipse(jdk 1.8), java, MACOS, Window10
# GitHub주소도 첨부하겠습니다
https://github.com/CEmmanuelP/chat-project.git
CEmmanuelP commented 5 years ago

오프라인으로 해결했습니다. @happydeveloper

happydeveloper commented 5 years ago

[시작버튼] Parent Class 와 child Class 를 생성할때 서로 연결해주시면 됩니다. public MultiClient(String argIp, String argId, Class connect)