您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關怎么在Java中利用GUI編程實現在線聊天室,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
客戶端的功能主要包括如下的功能:
選擇連上服務端
顯示當前房間列表(包括房間號和房間名稱)
選擇房間進入
多個用戶在線群聊
可以發送表情(用本地的,實際上發送只發送表情的代碼)
退出房間
選擇創建房間
房間里沒人(房主退出),導致房間解散
顯示系統提示消息
顯示用戶消息
構造標準的消息結構發送
維護GUI所需的數據模型
服務端的功能主要包括:
維護用戶信息和房間信息
處理用戶發送來的消息選擇轉發或者回復處理結果
構造標準的消息結構發送
架構
整個程序采用C/S設計架構,分為一個服務端和多個客戶端。服務端開放一個端口給所有開客戶端,客戶端連接該端口并收發信息,服務端在內部維護客戶端的組,并對每一個客戶端都用一個子線程來收發信息
基本類的設計
User類
package User; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; /** * * @author lannooo * */ public class User { private String name; private long id; private long roomId; private Socket socket; private BufferedReader br; private PrintWriter pw; /** * * @param name: 設置user的姓名 * @param id:設置user的id * @param socket:保存用戶連接的socket * @throws IOException */ public User(String name, long id, final Socket socket) throws IOException { this.name=name; this.id=id; this.socket=socket; this.br=new BufferedReader(new InputStreamReader( socket.getInputStream())); this.pw=new PrintWriter(socket.getOutputStream()); } /** * 獲得該用戶的id * @return id */ public long getId() { return id; } /** * 設置該用戶的id * @param id 新的id */ public void setId(long id) { this.id = id; } /** * 獲得用戶當前所在的房間號 * @return roomId */ public long getRoomId() { return roomId; } /** * 設置當前用戶的所在的房間號 * @param roomId */ public void setRoomId(long roomId) { this.roomId = roomId; } /** * 設置當前用戶在聊天室中的昵稱 * @param name */ public void setName(String name) { this.name = name; } /** * 返回當前用戶在房間中的昵稱 * @return */ public String getName() { return name; } /** * 返回當前用戶連接的socket實例 * @return */ public Socket getSocket() { return socket; } /** * 設置當前用戶連接的socket * @param socket */ public void setSocket(Socket socket) { this.socket = socket; } /** * 獲得該用戶的消息讀取輔助類BufferedReader實例 * @return */ public BufferedReader getBr() { return br; } /** * 設置 用戶的消息讀取輔助類 * @param br */ public void setBr(BufferedReader br) { this.br = br; } /** * 獲得消息寫入類實例 * @return */ public PrintWriter getPw() { return pw; } /** * 設置消息寫入類實例 * @param pw */ public void setPw(PrintWriter pw) { this.pw = pw; } /** * 重寫了用戶類打印的函數 */ @Override public String toString() { return "#User"+id+"#"+name+"[#Room"+roomId+"#]<socket:"+socket+">"; } }
Room類
package Room; import java.util.ArrayList; import java.util.List; import User.User; /** * * @author lannooo * */ public class Room { private String name; private long roomId; private ArrayList<User> list; private int totalUsers; /** * 獲得房間的名字 * @return name */ public String getName() { return name; } /** * 設置房間的新名字 * @param name */ public void setName(String name) { this.name = name; } /** * 獲得房間的id號 * @return */ public long getRoomId() { return roomId; } /** * 設置房間的id * @param roomId */ public void setRoomId(long roomId) { this.roomId = roomId; } /** * 向房間中加入一個新用戶 * @param user */ public void addUser(User user) { if(!list.contains(user)){ list.add(user); totalUsers++; }else{ System.out.println("User is already in Room<"+name+">:"+user); } } /** * 從房間中刪除一個用戶 * @param user * @return 目前該房間中的總用戶數目 */ public int delUser(User user){ if(list.contains(user)){ list.remove(user); return --totalUsers; }else{ System.out.println("User is not in Room<"+name+">:"+user); return totalUsers; } } /** * 獲得當前房間的用戶列表 * @return */ public ArrayList<User> getUsers(){ return list; } /** * 獲得當前房間的用戶昵稱的列表 * @return */ public String[] getUserNames(){ String[] userList = new String[list.size()]; int i=0; for(User each: list){ userList[i++]=each.getName(); } return userList; } /** * 使用房間的名稱和id來new一個房間 * @param name * @param roomId */ public Room(String name, long roomId) { this.name=name; this.roomId=roomId; this.totalUsers=0; list = new ArrayList<>(); } }
RoomList類
package Room; import java.awt.image.DirectColorModel; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import User.User; /** * * @author lannooo * */ public class RoomList { private HashMap<Long, Room> map; private long unusedRoomId; public static long MAX_ROOMS = 9999; private int totalRooms; /** * 未使用的roomid從1算起,起始的房間總數為0 */ public RoomList(){ map = new HashMap<>(); unusedRoomId = 1; totalRooms = 0; } /** * 創建一個新的房間,使用未使用的房間號進行創建,如果沒有可以使用的則就創建失敗 * @param name: 房間的名字 * @return 創建的房間的id */ public long createRoom(String name){ if(totalRooms<MAX_ROOMS){ if(name.length()==0){ name = ""+unusedRoomId; } Room room = new Room(name, unusedRoomId); map.put(unusedRoomId, room); totalRooms++; return unusedRoomId++; }else{ return -1; } } /** * 用戶加入一個房間 * @param user * @param roomID * @return */ public boolean join(User user, long roomID){ if(map.containsKey(roomID)){ map.get(roomID).addUser(user); return true; }else{ return false; } } /** * 用戶退出他的房間 * @param user * @param roomID * @return */ public int esc(User user, long roomID){ if(map.containsKey(roomID)){ int number = map.get(roomID).delUser(user); /*如果這個房間剩下的人數為0,那么刪除該房間*/ if(number==0){ map.remove(roomID); totalRooms--; return 0; } return 1; }else{ return -1; } } /** * 列出所有房間的列表,返回一個二維數組,strings[i][0]放房間的id,string[i][1]放房間的name * @return */ public String[][] listRooms(){ String[][] strings = new String[totalRooms][2]; int i=0; /*將map轉化為set并使用迭代器來遍歷*/ Set<Entry<Long, Room>> set = map.entrySet(); Iterator<Entry<Long, Room>> iterator = set.iterator(); while(iterator.hasNext()){ Map.Entry<Long, Room> entry = iterator.next(); long key = entry.getKey(); Room value = entry.getValue(); strings[i][0]=""+key; strings[i][1]=value.getName(); } return strings; } /** * 通過roomID來獲得房間 * @param roomID * @return */ public Room getRoom(long roomID){ if(map.containsKey(roomID)){ return map.get(roomID); } else return null; } }
服務端
Server
package Server; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.json.*; import Room.Room; import Room.RoomList; import User.User; /** * * @author lannooo * */ public class Server { private ArrayList<User> allUsers; private RoomList rooms; private int port; private ServerSocket ss; private long unusedUserID; public final long MAX_USERS = 999999; /** * 通過port號來構造服務器端對象 * 維護一個總的用戶列表和一個房間列表 * @param port * @throws Exception */ public Server(int port) throws Exception { allUsers = new ArrayList<>(); rooms = new RoomList(); this.port=port; unusedUserID=1; ss = new ServerSocket(port); System.out.println("Server is builded!"); } /** * 獲得下一個可用的用戶id * @return */ private long getNextUserID(){ if(unusedUserID < MAX_USERS) return unusedUserID++; else return -1; } /** * 開始監聽,當接受到新的用戶連接,就創建一個新的用戶,并添加到用戶列表中 * 然后創建一個新的服務線程用于收發該用戶的消息 * @throws Exception */ public void startListen() throws Exception{ while(true){ Socket socket = ss.accept(); long id = getNextUserID(); if(id != -1){ User user = new User("User"+id, id, socket); System.out.println(user.getName() + " is login..."); allUsers.add(user); ServerThread thread = new ServerThread(user, allUsers, rooms); thread.start(); }else{ System.out.println("Server is full!"); socket.close(); } } } /** * 測試用main方法,設置偵聽端口為9999,并開始監聽 * @param args */ public static void main(String[] args) { try { Server server = new Server(9999); server.startListen(); } catch (Exception e) { e.printStackTrace(); } } }
ServerThread
package Server; import java.io.IOException; import java.io.PrintWriter; import java.net.SocketException; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import Room.Room; import Room.RoomList; import User.User; /** * * @author lannooo * */ public class ServerThread extends Thread { private User user; private ArrayList<User> userList;/*保存用戶列表*/ private RoomList map; /*保存房間列表*/ private long roomId; private PrintWriter pw; /** * 通過用戶的對象實例、全局的用戶列表、房間列表進行構造 * @param user * @param userList * @param map */ public ServerThread(User user, ArrayList<User> userList, RoomList map){ this.user=user; this.userList=userList; this.map=map; pw=null; roomId = -1; } /** * 線程運行部分,持續讀取用戶socket發送來的數據,并解析 */ public void run(){ try{ while (true) { String msg=user.getBr().readLine(); System.out.println(msg); /*解析用戶的數據格式*/ parseMsg(msg); } }catch (SocketException se) { /*處理用戶斷開的異常*/ System.out.println("user "+user.getName()+" logout."); }catch (Exception e) { /*處理其他異常*/ e.printStackTrace(); }finally { try { /* * 用戶斷開或者退出,需要把該用戶移除 * 并關閉socket */ remove(user); user.getBr().close(); user.getSocket().close(); } catch (IOException ioe) { ioe.printStackTrace(); } } } /** * 用正則表達式匹配數據的格式,根據不同的指令類型,來調用相應的方法處理 * @param msg */ private void parseMsg(String msg){ String code = null; String message=null; if(msg.length()>0){ /*匹配指令類型部分的字符串*/ Pattern pattern = Pattern.compile("<code>(.*)</code>"); Matcher matcher = pattern.matcher(msg); if(matcher.find()){ code = matcher.group(1); } /*匹配消息部分的字符串*/ pattern = Pattern.compile("<msg>(.*)</msg>"); matcher = pattern.matcher(msg); if(matcher.find()){ message = matcher.group(1); } switch (code) { case "join": // add to the room // code = 1, 直接顯示在textArea中 // code = 11, 在list中加入 // code = 21, 把當前房間里的所有用戶返回給client if(roomId == -1){ roomId = Long.parseLong(message); map.join(user, roomId); sendRoomMsgExceptSelf(buildCodeWithMsg("<name>"+user.getName()+"</name><id>"+user.getId()+"</id>", 11)); // 這個消息需要加入房間里已有用戶的列表 returnMsg(buildCodeWithMsg("你加入了房間:" + map.getRoom(roomId).getName(), 1)); returnMsg(buildCodeWithMsg(getMembersInRoom(), 21)); }else{ map.esc(user, roomId); sendRoomMsg(buildCodeWithMsg(""+user.getId(), 12)); long oldRoomId = roomId; roomId = Long.parseLong(message); map.join(user, roomId); sendRoomMsgExceptSelf(buildCodeWithMsg("<name>"+user.getName()+"</name><id>"+user.getId()+"</id>", 11)); returnMsg(buildCodeWithMsg("你退出房間:" + map.getRoom(oldRoomId).getName() + ",并加入了房間:" + roomId,1)); returnMsg(buildCodeWithMsg(getMembersInRoom(), 21)); } break; case "esc": // delete from room list // code = 2, 彈窗提示 // code = 12, 對所有該房間的其他用戶發送該用戶退出房間的信息,從list中刪除 if(roomId!=-1){ int flag=map.esc(user, roomId); sendRoomMsgExceptSelf(buildCodeWithMsg(""+user.getId(), 12)); long oldRoomId=roomId; roomId = -1; returnMsg(buildCodeWithMsg("你已經成功退出房間,不會收到消息", 2)); if(flag==0){ sendMsg(buildCodeWithMsg(""+oldRoomId, 13)); } }else{ returnMsg(buildCodeWithMsg("你尚未加入任何房間", 2)); } break; case "list": // list all the rooms // code = 3, 在客戶端解析rooms,并填充roomlist returnMsg(buildCodeWithMsg(getRoomsList(), 3)); break; case "message": // send message // code = 4, 自己收到的話,打印的是‘你說:....'否則打印user id對應的name sendRoomMsg(buildCodeWithMsg("<from>"+user.getId()+"</from><smsg>"+message+"</smsg>", 4)); break; case "create": // create a room // code=5,提示用戶進入了房間 // code=15,需要在其他所有用戶的room列表中更新 roomId = map.createRoom(message); map.join(user, roomId); sendMsg(buildCodeWithMsg("<rid>"+roomId+"</rid><rname>"+message+"</rname>", 15)); returnMsg(buildCodeWithMsg("你進入了創建的房間:"+map.getRoom(roomId).getName(), 5)); returnMsg(buildCodeWithMsg(getMembersInRoom(), 21)); break; case "setname": // set name for user // code=16,告訴房間里的其他人,你改了昵稱 user.setName(message); sendRoomMsg(buildCodeWithMsg("<id>"+user.getId()+"</id><name>"+message+"</name>", 16)); break; default: // returnMsg("something unknown"); System.out.println("not valid message from user"+user.getId()); break; } } } /** * 獲得該用戶房間中的所有用戶列表,并構造成一定格式的消息返回 * @return */ private String getMembersInRoom(){ /*先從room列表獲得該用戶的room*/ Room room = map.getRoom(roomId); StringBuffer stringBuffer = new StringBuffer(); if(room != null){ /*獲得房間中所有的用戶的列表,然后構造成一定的格式發送回去*/ ArrayList<User> users = room.getUsers(); for(User each: users){ stringBuffer.append("<member><name>"+each.getName()+ "</name><id>"+each.getId()+"</id></member>"); } } return stringBuffer.toString(); } /** * 獲得所有房間的列表,并構造成一定的格式 * @return */ private String getRoomsList(){ String[][] strings = map.listRooms(); StringBuffer sb = new StringBuffer(); for(int i=0; i<strings.length; i++){ sb.append("<room><rname>"+strings[i][1]+ "</rname><rid>"+strings[i][0]+"</rid></room>"); } return sb.toString(); } /** * 構造成一個統一的消息格式 * @param msg * @param code * @return */ private String buildCodeWithMsg(String msg, int code){ return "<code>"+code+"</code><msg>"+msg+"</msg>\n"; } /** * 這個是群發消息:全體用戶,code>10 * @param msg */ private void sendMsg(String msg) { // System.out.println("In sendMsg()"); /*取出用戶列表中的每一個用戶來發送消息*/ for(User each:userList){ try { pw=each.getPw(); pw.println(msg); pw.flush(); System.out.println(msg); } catch (Exception e) { System.out.println("exception in sendMsg()"); } } } /** * 只對同一房間的用戶發:code>10 * @param msg */ private void sendRoomMsg(String msg){ /*先獲得該用戶的房間號,然后往該房間發送消息*/ Room room = map.getRoom(roomId); if(room != null){ ArrayList<User> users = room.getUsers(); for(User each: users){ pw = each.getPw(); pw.println(msg); pw.flush(); } } } /** * 向房間中除了該用戶自己,發送消息 * @param msg */ private void sendRoomMsgExceptSelf(String msg){ Room room = map.getRoom(roomId); if(room != null){ ArrayList<User> users = room.getUsers(); for(User each: users){ if(each.getId()!=user.getId()){ pw = each.getPw(); pw.println(msg); pw.flush(); } } } } /** * 對于client的來信,返回一個結果,code<10 * @param msg */ private void returnMsg(String msg){ try{ pw = user.getPw(); pw.println(msg); pw.flush(); }catch (Exception e) { System.out.println("exception in returnMsg()"); } } /** * 移除該用戶,并向房間中其他用戶發送該用戶已經退出的消息 * 如果房間中沒人了,那么就更新房間列表給所有用戶 * @param user */ private void remove(User user){ if(roomId!=-1){ int flag=map.esc(user, roomId); sendRoomMsgExceptSelf(buildCodeWithMsg(""+user.getId(), 12)); long oldRoomId=roomId; roomId = -1; if(flag==0){ sendMsg(buildCodeWithMsg(""+oldRoomId, 13)); } } userList.remove(user); } }
客戶端
Client
package Client; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.DefaultListModel; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.text.BadLocationException; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; /** * * @author lannooo * */ public class Client implements ActionListener{ private JFrame frame; private Socket socket; private BufferedReader br; private PrintWriter pw; private String name; private HashMap<String, Integer> rooms_map; private HashMap<String, Integer> users_map; private JTextField host_textfield; private JTextField port_textfield; private JTextField text_field; private JTextField name_textfiled; private JLabel rooms_label; private JLabel users_label; private JList<String> roomlist; private JList<String> userlist; private JTextPane msgArea; private JScrollPane textScrollPane; private JScrollBar vertical; DefaultListModel<String> rooms_model; DefaultListModel<String> users_model; /* * 構造函數 * 該客戶端對象維護兩個map,房間的hashmap和房間中用戶的hashmap * 作為列表組件的數據模型 */ public Client(){ rooms_map = new HashMap<>(); users_map = new HashMap<>(); initialize(); } /** * 連接服務端,指定host和port * @param host * @param port * @return */ public boolean connect(String host, int port){ try { socket = new Socket(host, port); System.out.println("Connected to server!"+socket.getRemoteSocketAddress()); br=new BufferedReader(new InputStreamReader(System.in)); pw=new PrintWriter(socket.getOutputStream()); /* * 創建一個接受和解析服務器消息的線程 * 傳入當前客戶端對象的指針,作為句柄調用相應的處理函數 */ ClientThread thread = new ClientThread(socket, this); thread.start(); return true; } catch (IOException e) { System.out.println("Server error"); JOptionPane.showMessageDialog(frame, "服務器無法連接!"); return false; } } /*當前進程作為只發送消息的線程,從命令行中獲取輸入*/ // public void sendMsg(){ // String msg; // try { // while(true){ // msg = br.readLine(); // pw.println(msg); // pw.flush(); // } // } catch (IOException e) { // System.out.println("error when read msg and to send."); // } // } /** * 發給服務器的消息,先經過一定的格式構造再發送 * @param msg * @param code */ public void sendMsg(String msg, String code){ try { pw.println("<code>"+code+"</code><msg>"+msg+"</msg>"); pw.flush(); } catch (Exception e) { //一般是沒有連接的問題 System.out.println("error in sendMsg()"); JOptionPane.showMessageDialog(frame, "請先連接服務器!"); } } /** * 窗口初始化 */ private void initialize() { /*設置窗口的UI風格和字體*/ setUIStyle(); setUIFont(); JFrame frame = new JFrame("ChatOnline"); JPanel panel = new JPanel(); /*主要的panel,上層放置連接區,下層放置消息區, 中間是消息面板,左邊是room列表,右邊是當前room的用戶列表*/ JPanel headpanel = new JPanel(); /*上層panel,用于放置連接區域相關的組件*/ JPanel footpanel = new JPanel(); /*下層panel,用于放置發送信息區域的組件*/ JPanel leftpanel = new JPanel(); /*左邊panel,用于放置房間列表和加入按鈕*/ JPanel rightpanel = new JPanel(); /*右邊panel,用于放置房間內人的列表*/ /*最上層的布局,分中間,東南西北五個部分*/ BorderLayout layout = new BorderLayout(); /*格子布局,主要用來設置西、東、南三個部分的布局*/ GridBagLayout gridBagLayout = new GridBagLayout(); /*主要設置北部的布局*/ FlowLayout flowLayout = new FlowLayout(); /*設置初始窗口的一些性質*/ frame.setBounds(100, 100, 800, 600); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setContentPane(panel); frame.setLayout(layout); /*設置各個部分的panel的布局和大小*/ headpanel.setLayout(flowLayout); footpanel.setLayout(gridBagLayout); leftpanel.setLayout(gridBagLayout); rightpanel.setLayout(gridBagLayout); leftpanel.setPreferredSize(new Dimension(130, 0)); rightpanel.setPreferredSize(new Dimension(130, 0)); /*以下均是headpanel中的組件*/ host_textfield = new JTextField("127.0.0.1"); port_textfield = new JTextField("9999"); name_textfiled = new JTextField("匿名"); host_textfield.setPreferredSize(new Dimension(100, 25)); port_textfield.setPreferredSize(new Dimension(70, 25)); name_textfiled.setPreferredSize(new Dimension(150, 25)); JLabel host_label = new JLabel("服務器IP"); JLabel port_label = new JLabel("端口"); JLabel name_label = new JLabel("昵稱"); JButton head_connect = new JButton("連接"); // JButton head_change = new JButton("確認更改"); JButton head_create = new JButton("創建房間"); headpanel.add(host_label); headpanel.add(host_textfield); headpanel.add(port_label); headpanel.add(port_textfield); headpanel.add(head_connect); headpanel.add(name_label); headpanel.add(name_textfiled); // headpanel.add(head_change); headpanel.add(head_create); /*以下均是footpanel中的組件*/ JButton foot_emoji = new JButton("表情"); JButton foot_send = new JButton("發送"); text_field = new JTextField(); footpanel.add(text_field, new GridBagConstraints(0, 0, 1, 1, 100, 100, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); footpanel.add(foot_emoji, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); footpanel.add(foot_send, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); /*兩邊的格子中的組件*/ rooms_label = new JLabel("當前房間數:0"); users_label = new JLabel("房間內人數:0"); JButton join_button = new JButton("加入房間"); JButton esc_button = new JButton("退出房間"); rooms_model = new DefaultListModel<>(); users_model = new DefaultListModel<>(); // rooms_model.addElement("房間1"); // rooms_model.addElement("房間2"); // rooms_model.addElement("房間3"); // String fangjian = "房間1"; // rooms_map.put(fangjian, 1); roomlist = new JList<>(rooms_model); userlist = new JList<>(users_model); JScrollPane roomListPane = new JScrollPane(roomlist); JScrollPane userListPane = new JScrollPane(userlist); leftpanel.add(rooms_label, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); leftpanel.add(join_button, new GridBagConstraints(0, 1, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); leftpanel.add(esc_button, new GridBagConstraints(0, 2, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); leftpanel.add(roomListPane, new GridBagConstraints(0, 3, 1, 1, 100, 100, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); rightpanel.add(users_label, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); rightpanel.add(userListPane,new GridBagConstraints(0, 1, 1, 1, 100, 100, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); /*中間的文本區組件*/ msgArea = new JTextPane(); msgArea.setEditable(false); textScrollPane = new JScrollPane(); textScrollPane.setViewportView(msgArea); vertical = new JScrollBar(JScrollBar.VERTICAL); vertical.setAutoscrolls(true); textScrollPane.setVerticalScrollBar(vertical); /*設置頂層布局*/ panel.add(headpanel, "North"); panel.add(footpanel, "South"); panel.add(leftpanel, "West"); panel.add(rightpanel, "East"); panel.add(textScrollPane, "Center"); /*注冊各種事件*/ /*連接服務器*/ head_connect.addActionListener(this); /*發送消息,如果沒有連接則會彈窗提示*/ foot_send.addActionListener(this); /*改名字*/ // head_change.addActionListener(this); /*創建房間*/ head_create.addActionListener(this); /*發送表情*/ foot_emoji.addActionListener(this); /*加入room*/ join_button.addActionListener(this); /*退出房間*/ esc_button.addActionListener(this); /*最終顯示*/ frame.setVisible(true); } /** * 事件監聽處理 */ @Override public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); switch (cmd) { case "連接": /*點擊連接按鈕*/ String strhost = host_textfield.getText(); String strport = port_textfield.getText(); connect(strhost, Integer.parseInt(strport)); String nameSeted = JOptionPane.showInputDialog("請輸入你的昵稱:"); /*提示輸入昵稱*/ name_textfiled.setText(nameSeted); name_textfiled.setEditable(false); port_textfield.setEditable(false); host_textfield.setEditable(false); /*發送設置姓名的消息和列出用戶列表的消息*/ sendMsg(nameSeted, "setname"); sendMsg("", "list"); break; // case "確認更改": // String strname = name_textfiled.getText(); // name = strname; // sendMsg(strname, "setname"); // break; case "加入房間": /*選擇房間后,點擊加入房間按鈕*/ String selected = roomlist.getSelectedValue(); if(rooms_map.containsKey(selected)){ sendMsg(""+rooms_map.get(selected), "join"); } break; case "退出房間": /*點擊退出房間的按鈕*/ sendMsg("", "esc"); break; case "發送": /*點擊發送消息的按鈕*/ String text = text_field.getText(); text_field.setText(""); sendMsg(text, "message"); break; case "表情": /*發送表情,新建一個表情窗口,并直接在表情窗口中處理消息發送*/ IconDialog dialog = new IconDialog(frame, this); break; case "創建房間": /*點擊創建房間的按鈕,彈出提示框數據房間名稱*/ String string = JOptionPane.showInputDialog("請輸入你的房間名稱"); if(string==null || string.equals("")){ string = name+(int)(Math.random()*10000)+"的房間"; } sendMsg(string, "create"); break; default: break; } } /*很多輔助和clientThread互動的*/ /** * 加入用戶,通過正則表達式,匹配消息內容中的用戶信息 * @param content */ public void addUser(String content){ if(content.length()>0){ Pattern pattern = Pattern.compile("<name>(.*)</name><id>(.*)</id>"); Matcher matcher = pattern.matcher(content); if(matcher.find()){ /* * 獲得用戶的name和id * 加入用戶列表 * 在消息區顯示系統提示 */ String name = matcher.group(1); String id = matcher.group(2); insertUser(Integer.parseInt(id), name); insertMessage(textScrollPane, msgArea, null, "系統:", name+"加入了聊天室"); } } users_label.setText("房間內人數:"+users_map.size()); /*更新房間內的人數*/ } /** * 刪除用戶 * @param content */ public void delUser(String content){ if(content.length()>0){ int id = Integer.parseInt(content); /* * 從維護的用戶map中取得所有的用戶名字,然后去遍歷匹配的用戶 * 匹配到的用戶名字從相應的數據模型中移除 * 并從map中移除,并在消息框中提示系統消息 */ Set<String> set = users_map.keySet(); Iterator<String> iter = set.iterator(); String name=null; while(iter.hasNext()){ name = iter.next(); if(users_map.get(name)==id){ users_model.removeElement(name); break; } } users_map.remove(name); insertMessage(textScrollPane, msgArea, null, "系統:", name+"退出了聊天室"); } users_label.setText("房間內人數:"+users_map.size()); } /** * 更新用戶信息 * @param content */ public void updateUser(String content){ if(content.length()>0){ Pattern pattern = Pattern.compile("<id>(.*)</id><name>(.*)</name>"); Matcher matcher = pattern.matcher(content); if(matcher.find()){ String id = matcher.group(1); String name = matcher.group(2); insertUser(Integer.parseInt(id), name); } } } /** * 列出所有用戶 * @param content */ public void listUsers(String content){ String name = null; String id=null; Pattern rough_pattern=null; Matcher rough_matcher=null; Pattern detail_pattern=null; /* * 先用正則表達式匹配用戶信息 * 然后插入數據模型中 * 并更新用戶數據模型中的條目 */ if(content.length()>0){ rough_pattern = Pattern.compile("<member>(.*?)</member>"); rough_matcher = rough_pattern.matcher(content); while(rough_matcher.find()){ String detail = rough_matcher.group(1); detail_pattern = Pattern.compile("<name>(.*)</name><id>(.*)</id>"); Matcher detail_matcher = detail_pattern.matcher(detail); if(detail_matcher.find()){ name = detail_matcher.group(1); id = detail_matcher.group(2); insertUser(Integer.parseInt(id), name); } } } users_label.setText("房間內人數:"+users_map.size()); } /** * 直接在textarea中顯示消息 * @param content */ public void updateTextArea(String content){ insertMessage(textScrollPane, msgArea, null, "系統:", content); } /** * 在textarea中顯示其他用戶的消息 * 先用正則匹配,再顯示消息 * 其中還需要匹配emoji表情的編號 * @param content */ public void updateTextAreaFromUser(String content){ if(content.length()>0){ Pattern pattern = Pattern.compile("<from>(.*)</from><smsg>(.*)</smsg>"); Matcher matcher = pattern.matcher(content); if(matcher.find()){ String from = matcher.group(1); String smsg = matcher.group(2); String fromName = getUserName(from); if(fromName.equals(name)) fromName = "你"; if(smsg.startsWith("<emoji>")){ String emojiCode = smsg.substring(7, smsg.length()-8); // System.out.println(emojiCode); insertMessage(textScrollPane, msgArea, emojiCode, fromName+"說:", null); return ; } insertMessage(textScrollPane, msgArea, null, fromName+"說:", smsg); } } } /** * 顯示退出的結果 * @param content */ public void showEscDialog(String content){ JOptionPane.showMessageDialog(frame, content); /*清除消息區內容,清除用戶數據模型內容和用戶map內容,更新房間內人數*/ msgArea.setText(""); users_model.clear(); users_map.clear(); users_label.setText("房間內人數:0"); } /** * 新增一個room * @param content */ public void addRoom(String content){ if(content.length()>0){ Pattern pattern = Pattern.compile("<rid>(.*)</rid><rname>(.*)</rname>"); Matcher matcher = pattern.matcher(content); if(matcher.find()){ String rid = matcher.group(1); String rname = matcher.group(2); insertRoom(Integer.parseInt(rid), rname); } } rooms_label.setText("當前房間數:"+rooms_map.size()); } /** * 刪除一個room * @param content */ public void delRoom(String content){ if(content.length()>0){ int delRoomId = Integer.parseInt(content); Set<String> set = rooms_map.keySet(); Iterator<String> iter = set.iterator(); String rname=null; while(iter.hasNext()){ rname = iter.next(); if(rooms_map.get(rname)==delRoomId){ rooms_model.removeElement(rname); break; } } rooms_map.remove(rname); } rooms_label.setText("當前房間數:"+rooms_map.size()); } /** * 列出目前所有的rooms * @param content */ public void listRooms(String content){ String rname = null; String rid=null; Pattern rough_pattern=null; Matcher rough_matcher=null; Pattern detail_pattern=null; if(content.length()>0){ rough_pattern = Pattern.compile("<room>(.*?)</room>"); rough_matcher = rough_pattern.matcher(content); while(rough_matcher.find()){ String detail = rough_matcher.group(1); detail_pattern = Pattern.compile("<rname>(.*)</rname><rid>(.*)</rid>"); Matcher detail_matcher = detail_pattern.matcher(detail); if(detail_matcher.find()){ rname = detail_matcher.group(1); rid = detail_matcher.group(2); insertRoom(Integer.parseInt(rid), rname); } } } rooms_label.setText("當前房間數:"+rooms_map.size()); } /** * 插入一個room * @param rid * @param rname */ private void insertRoom(Integer rid, String rname){ if(!rooms_map.containsKey(rname)){ rooms_map.put(rname, rid); rooms_model.addElement(rname); }else{ rooms_map.remove(rname); rooms_model.removeElement(rname); rooms_map.put(rname, rid); rooms_model.addElement(rname); } rooms_label.setText("當前房間數:"+rooms_map.size()); } /** * 插入一個user * @param id * @param name */ private void insertUser(Integer id, String name){ if(!users_map.containsKey(name)){ users_map.put(name, id); users_model.addElement(name); }else{ users_map.remove(name); users_model.removeElement(name); users_map.put(name, id); users_model.addElement(name); } users_label.setText("房間內人數:"+users_map.size()); } /** * 獲得用戶的姓名 * @param strId * @return */ private String getUserName(String strId){ int uid = Integer.parseInt(strId); Set<String> set = users_map.keySet(); Iterator<String> iterator = set.iterator(); String cur=null; while(iterator.hasNext()){ cur = iterator.next(); if(users_map.get(cur)==uid){ return cur; } } return ""; } /** * 獲得用戶所在房間的名稱 * @param strId * @return */ private String getRoomName(String strId){ int rid = Integer.parseInt(strId); Set<String> set = rooms_map.keySet(); Iterator<String> iterator = set.iterator(); String cur = null; while(iterator.hasNext()){ cur = iterator.next(); if(rooms_map.get(cur)==rid){ return cur; } } return ""; } /** * 打印一條消息,如果有圖片就打印圖片,否則打印content * @param scrollPane * @param textPane * @param icon_code * @param title * @param content */ private void insertMessage(JScrollPane scrollPane, JTextPane textPane, String icon_code, String title, String content){ StyledDocument document = textPane.getStyledDocument(); /*獲取textpane中的文本*/ /*設置標題的屬性*/ SimpleAttributeSet title_attr = new SimpleAttributeSet(); StyleConstants.setBold(title_attr, true); StyleConstants.setForeground(title_attr, Color.BLUE); /*設置正文的屬性*/ SimpleAttributeSet content_attr = new SimpleAttributeSet(); StyleConstants.setBold(content_attr, false); StyleConstants.setForeground(content_attr, Color.BLACK); Style style = null; if(icon_code!=null){ Icon icon = new ImageIcon("icon/"+icon_code+".png"); style = document.addStyle("icon", null); StyleConstants.setIcon(style, icon); } try { document.insertString(document.getLength(), title+"\n", title_attr); if(style!=null) document.insertString(document.getLength(), "\n", style); else document.insertString(document.getLength(), " "+content+"\n", content_attr); } catch (BadLocationException ex) { System.out.println("Bad location exception"); } /*設置滑動條到最后*/ vertical.setValue(vertical.getMaximum()); } /** * 設置需要美化字體的組件 */ public static void setUIFont() { Font f = new Font("微軟雅黑", Font.PLAIN, 14); String names[]={ "Label", "CheckBox", "PopupMenu","MenuItem", "CheckBoxMenuItem", "JRadioButtonMenuItem","ComboBox", "Button", "Tree", "ScrollPane", "TabbedPane", "EditorPane", "TitledBorder", "Menu", "TextArea","TextPane", "OptionPane", "MenuBar", "ToolBar", "ToggleButton", "ToolTip", "ProgressBar", "TableHeader", "Panel", "List", "ColorChooser", "PasswordField","TextField", "Table", "Label", "Viewport", "RadioButtonMenuItem","RadioButton", "DesktopPane", "InternalFrame" }; for (String item : names) { UIManager.put(item+ ".font",f); } } /** * 設置UI風格為當前系統的風格 */ public static void setUIStyle(){ String lookAndFeel =UIManager.getSystemLookAndFeelClassName(); try { UIManager.setLookAndFeel(lookAndFeel); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnsupportedLookAndFeelException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 測試用的main函數 * @param args */ public static void main(String[] args) { Client client = new Client(); } }
ClientThread
package Client; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * * @author lannooo * */ public class ClientThread extends Thread{ private Socket socket; private Client client; private BufferedReader br; private PrintWriter pw; /** * 從過主線程傳入的socket和client對象來構造 * @param socket * @param client */ public ClientThread(Socket socket, Client client){ this.client = client; this.socket = socket; try { br=new BufferedReader(new InputStreamReader(socket.getInputStream())); } catch (IOException e) { System.out.println("cannot get inputstream from socket."); } } /** * 不斷的讀數據并處理 * 調用主線程的方法來處理:client.method(); */ public void run() { try{ br=new BufferedReader(new InputStreamReader(socket.getInputStream())); while(true){ String msg = br.readLine(); parseMessage(msg); } }catch (Exception e) { e.printStackTrace(); } } /** * 處理從服務器收到的消息 * @param message */ public void parseMessage(String message){ String code = null; String msg=null; /* * 先用正則表達式匹配code碼和msg內容 */ if(message.length()>0){ Pattern pattern = Pattern.compile("<code>(.*)</code>"); Matcher matcher = pattern.matcher(message); if(matcher.find()){ code = matcher.group(1); } pattern = Pattern.compile("<msg>(.*)</msg>"); matcher = pattern.matcher(message); if(matcher.find()){ msg = matcher.group(1); } System.out.println(code+":"+msg); switch(code){ case "1": /*一個普通消息處理*/ client.updateTextArea(msg); break; case "2": /*退出消息*/ client.showEscDialog(msg); break; case "3": /*列出房間*/ client.listRooms(msg); break; case "4": /*其他用戶的消息*/ client.updateTextAreaFromUser(msg); break; case "5": /*普通消息處理*/ client.updateTextArea(msg); break; case "11": /*添加用戶*/ client.addUser(msg); break; case "12": /*刪除用戶*/ client.delUser(msg); break; case "13": /*刪除房間*/ client.delRoom(msg); break; case "15": /*添加房間*/ client.addRoom(msg); break; case "16": /*更新用戶名稱*/ client.updateUser(msg); break; case "21": /*列出用戶列表*/ client.listUsers(msg); break; } } } }
IconDialog(選擇表情界面)
package Client; import java.awt.Container; import java.awt.Dialog; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; /** * * @author lannooo * */ public class IconDialog implements ActionListener { private JDialog dialog; private Client client; /** * 通過frame和客戶端對象來構造 * @param frame * @param client */ public IconDialog(JFrame frame, Client client) { this.client = client; dialog = new JDialog(frame, "請選擇表情", true); /*16個表情*/ JButton[] icon_button = new JButton[16]; ImageIcon[] icons = new ImageIcon[16]; /*獲得彈出窗口的容器,設置布局*/ Container dialogPane = dialog.getContentPane(); dialogPane.setLayout(new GridLayout(0, 4)); /*加入表情*/ for(int i=1; i<=15; i++){ icons[i] = new ImageIcon("icon/"+i+".png"); icons[i].setImage(icons[i].getImage().getScaledInstance(50, 50, Image.SCALE_DEFAULT)); icon_button[i] = new JButton(""+i, icons[i]); icon_button[i].addActionListener(this); dialogPane.add(icon_button[i]); } dialog.setBounds(200,266,266,280); dialog.show(); } @Override public void actionPerformed(ActionEvent e) { /*構造emoji結構的消息發送*/ String cmd = e.getActionCommand(); System.out.println(cmd); dialog.dispose(); client.sendMsg("<emoji>"+cmd+"</emoji>", "message"); } }
關于怎么在Java中利用GUI編程實現在線聊天室就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。