Java GUI编程实现在线聊天室
引言
综合应用Java的GUI编程和网络编程,实现一个能够支持多组用户同时使用的聊天室软件。该聊天室具有比较友好的GUI界面,并使用C/S模式,支持多个用户同时使用,用户可以自己选择加入或者创建房间,和房间内的其他用户互发信息(文字和图片)
主要功能
客户端的功能主要包括如下的功能:
- 选择连上服务端
- 显示当前房间列表(包括房间号和房间名称)
- 选择房间进入
- 多个用户在线群聊
- 可以发送表情(用本地的,实际上发送只发送表情的代码)
- 退出房间
- 选择创建房间
- 房间里没人(房主退出),导致房间解散
- 显示系统提示消息
- 显示用户消息
- 构造标准的消息结构发送
- 维护GUI所需的数据模型
服务端的功能主要包括:
- 维护用户信息和房间信息
- 处理用户发送来的消息选择转发或者回复处理结果
- 构造标准的消息结构发送
架构
整个程序采用C/S设计架构,分为一个服务端和多个客户端。服务端开放一个端口给所有开客户端,客户端连接该端口并收发信息,服务端在内部维护客户端的组,并对每一个客户端都用一个子线程来收发信息
基本类的设计
User类
packageUser;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.io.PrintWriter;
importjava.net.Socket;
/**
*
*@authorlannooo
*
*/
publicclassUser{
privateStringname;
privatelongid;
privatelongroomId;
privateSocketsocket;
privateBufferedReaderbr;
privatePrintWriterpw;
/**
*
*@paramname:设置user的姓名
*@paramid:设置user的id
*@paramsocket:保存用户连接的socket
*@throwsIOException
*/
publicUser(Stringname,longid,finalSocketsocket)throwsIOException{
this.name=name;
this.id=id;
this.socket=socket;
this.br=newBufferedReader(newInputStreamReader(
socket.getInputStream()));
this.pw=newPrintWriter(socket.getOutputStream());
}
/**
*获得该用户的id
*@returnid
*/
publiclonggetId(){
returnid;
}
/**
*设置该用户的id
*@paramid新的id
*/
publicvoidsetId(longid){
this.id=id;
}
/**
*获得用户当前所在的房间号
*@returnroomId
*/
publiclonggetRoomId(){
returnroomId;
}
/**
*设置当前用户的所在的房间号
*@paramroomId
*/
publicvoidsetRoomId(longroomId){
this.roomId=roomId;
}
/**
*设置当前用户在聊天室中的昵称
*@paramname
*/
publicvoidsetName(Stringname){
this.name=name;
}
/**
*返回当前用户在房间中的昵称
*@return
*/
publicStringgetName(){
returnname;
}
/**
*返回当前用户连接的socket实例
*@return
*/
publicSocketgetSocket(){
returnsocket;
}
/**
*设置当前用户连接的socket
*@paramsocket
*/
publicvoidsetSocket(Socketsocket){
this.socket=socket;
}
/**
*获得该用户的消息读取辅助类BufferedReader实例
*@return
*/
publicBufferedReadergetBr(){
returnbr;
}
/**
*设置用户的消息读取辅助类
*@parambr
*/
publicvoidsetBr(BufferedReaderbr){
this.br=br;
}
/**
*获得消息写入类实例
*@return
*/
publicPrintWritergetPw(){
returnpw;
}
/**
*设置消息写入类实例
*@parampw
*/
publicvoidsetPw(PrintWriterpw){
this.pw=pw;
}
/**
*重写了用户类打印的函数
*/
@Override
publicStringtoString(){
return"#User"+id+"#"+name+"[#Room"+roomId+"#]";
}
}
Room类
packageRoom;
importjava.util.ArrayList;
importjava.util.List;
importUser.User;
/**
*
*@authorlannooo
*
*/
publicclassRoom{
privateStringname;
privatelongroomId;
privateArrayListlist;
privateinttotalUsers;
/**
*获得房间的名字
*@returnname
*/
publicStringgetName(){
returnname;
}
/**
*设置房间的新名字
*@paramname
*/
publicvoidsetName(Stringname){
this.name=name;
}
/**
*获得房间的id号
*@return
*/
publiclonggetRoomId(){
returnroomId;
}
/**
*设置房间的id
*@paramroomId
*/
publicvoidsetRoomId(longroomId){
this.roomId=roomId;
}
/**
*向房间中加入一个新用户
*@paramuser
*/
publicvoidaddUser(Useruser){
if(!list.contains(user)){
list.add(user);
totalUsers++;
}else{
System.out.println("UserisalreadyinRoom<"+name+">:"+user);
}
}
/**
*从房间中删除一个用户
*@paramuser
*@return目前该房间中的总用户数目
*/
publicintdelUser(Useruser){
if(list.contains(user)){
list.remove(user);
return--totalUsers;
}else{
System.out.println("UserisnotinRoom<"+name+">:"+user);
returntotalUsers;
}
}
/**
*获得当前房间的用户列表
*@return
*/
publicArrayListgetUsers(){
returnlist;
}
/**
*获得当前房间的用户昵称的列表
*@return
*/
publicString[]getUserNames(){
String[]userList=newString[list.size()];
inti=0;
for(Usereach:list){
userList[i++]=each.getName();
}
returnuserList;
}
/**
*使用房间的名称和id来new一个房间
*@paramname
*@paramroomId
*/
publicRoom(Stringname,longroomId){
this.name=name;
this.roomId=roomId;
this.totalUsers=0;
list=newArrayList<>();
}
}
RoomList类
packageRoom;
importjava.awt.image.DirectColorModel;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Map;
importjava.util.Map.Entry;
importjava.util.Set;
importUser.User;
/**
*
*@authorlannooo
*
*/
publicclassRoomList{
privateHashMapmap;
privatelongunusedRoomId;
publicstaticlongMAX_ROOMS=9999;
privateinttotalRooms;
/**
*未使用的roomid从1算起,起始的房间总数为0
*/
publicRoomList(){
map=newHashMap<>();
unusedRoomId=1;
totalRooms=0;
}
/**
*创建一个新的房间,使用未使用的房间号进行创建,如果没有可以使用的则就创建失败
*@paramname:房间的名字
*@return创建的房间的id
*/
publiclongcreateRoom(Stringname){
if(totalRooms>set=map.entrySet();
Iterator>iterator=set.iterator();
while(iterator.hasNext()){
Map.Entryentry=iterator.next();
longkey=entry.getKey();
Roomvalue=entry.getValue();
strings[i][0]=""+key;
strings[i][1]=value.getName();
}
returnstrings;
}
/**
*通过roomID来获得房间
*@paramroomID
*@return
*/
publicRoomgetRoom(longroomID){
if(map.containsKey(roomID)){
returnmap.get(roomID);
}
else
returnnull;
}
}
服务端
Server
packageServer;
importjava.net.ServerSocket;
importjava.net.Socket;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.Map;
importorg.json.*;
importRoom.Room;
importRoom.RoomList;
importUser.User;
/**
*
*@authorlannooo
*
*/
publicclassServer{
privateArrayListallUsers;
privateRoomListrooms;
privateintport;
privateServerSocketss;
privatelongunusedUserID;
publicfinallongMAX_USERS=999999;
/**
*通过port号来构造服务器端对象
*维护一个总的用户列表和一个房间列表
*@paramport
*@throwsException
*/
publicServer(intport)throwsException{
allUsers=newArrayList<>();
rooms=newRoomList();
this.port=port;
unusedUserID=1;
ss=newServerSocket(port);
System.out.println("Serverisbuilded!");
}
/**
*获得下一个可用的用户id
*@return
*/
privatelonggetNextUserID(){
if(unusedUserID
ServerThread
packageServer;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.net.SocketException;
importjava.util.ArrayList;
importjava.util.regex.Matcher;
importjava.util.regex.Pattern;
importRoom.Room;
importRoom.RoomList;
importUser.User;
/**
*
*@authorlannooo
*
*/
publicclassServerThreadextendsThread{
privateUseruser;
privateArrayListuserList;/*保存用户列表*/
privateRoomListmap;/*保存房间列表*/
privatelongroomId;
privatePrintWriterpw;
/**
*通过用户的对象实例、全局的用户列表、房间列表进行构造
*@paramuser
*@paramuserList
*@parammap
*/
publicServerThread(Useruser,
ArrayListuserList,RoomListmap){
this.user=user;
this.userList=userList;
this.map=map;
pw=null;
roomId=-1;
}
/**
*线程运行部分,持续读取用户socket发送来的数据,并解析
*/
publicvoidrun(){
try{
while(true){
Stringmsg=user.getBr().readLine();
System.out.println(msg);/*解析用户的数据格式*/
parseMsg(msg);
}
}catch(SocketExceptionse){/*处理用户断开的异常*/
System.out.println("user"+user.getName()+"logout.");
}catch(Exceptione){/*处理其他异常*/
e.printStackTrace();
}finally{
try{
/*
*用户断开或者退出,需要把该用户移除
*并关闭socket
*/
remove(user);
user.getBr().close();
user.getSocket().close();
}catch(IOExceptionioe){
ioe.printStackTrace();
}
}
}
/**
*用正则表达式匹配数据的格式,根据不同的指令类型,来调用相应的方法处理
*@parammsg
*/
privatevoidparseMsg(Stringmsg){
Stringcode=null;
Stringmessage=null;
if(msg.length()>0){
/*匹配指令类型部分的字符串*/
Patternpattern=Pattern.compile("(.*)");
Matchermatcher=pattern.matcher(msg);
if(matcher.find()){
code=matcher.group(1);
}
/*匹配消息部分的字符串*/
pattern=Pattern.compile("(.*) ");
matcher=pattern.matcher(msg);
if(matcher.find()){
message=matcher.group(1);
}
switch(code){
case"join":
//addtotheroom
//code=1,直接显示在textArea中
//code=11,在list中加入
//code=21,把当前房间里的所有用户返回给client
if(roomId==-1){
roomId=Long.parseLong(message);
map.join(user,roomId);
sendRoomMsgExceptSelf(buildCodeWithMsg(""+user.getName()+" "+user.getId()+" ",11));
//这个消息需要加入房间里已有用户的列表
returnMsg(buildCodeWithMsg("你加入了房间:"+map.getRoom(roomId).getName(),1));
returnMsg(buildCodeWithMsg(getMembersInRoom(),21));
}else{
map.esc(user,roomId);
sendRoomMsg(buildCodeWithMsg(""+user.getId(),12));
longoldRoomId=roomId;
roomId=Long.parseLong(message);
map.join(user,roomId);
sendRoomMsgExceptSelf(buildCodeWithMsg(""+user.getName()+" "+user.getId()+" ",11));
returnMsg(buildCodeWithMsg("你退出房间:"+map.getRoom(oldRoomId).getName()+",并加入了房间:"+roomId,1));
returnMsg(buildCodeWithMsg(getMembersInRoom(),21));
}
break;
case"esc":
//deletefromroomlist
//code=2,弹窗提示
//code=12,对所有该房间的其他用户发送该用户退出房间的信息,从list中删除
if(roomId!=-1){
intflag=map.esc(user,roomId);
sendRoomMsgExceptSelf(buildCodeWithMsg(""+user.getId(),12));
longoldRoomId=roomId;
roomId=-1;
returnMsg(buildCodeWithMsg("你已经成功退出房间,不会收到消息",2));
if(flag==0){
sendMsg(buildCodeWithMsg(""+oldRoomId,13));
}
}else{
returnMsg(buildCodeWithMsg("你尚未加入任何房间",2));
}
break;
case"list":
//listalltherooms
//code=3,在客户端解析rooms,并填充roomlist
returnMsg(buildCodeWithMsg(getRoomsList(),3));
break;
case"message":
//sendmessage
//code=4,自己收到的话,打印的是‘你说:....'否则打印userid对应的name
sendRoomMsg(buildCodeWithMsg(""+user.getId()+" "+message+" ",4));
break;
case"create":
//createaroom
//code=5,提示用户进入了房间
//code=15,需要在其他所有用户的room列表中更新
roomId=map.createRoom(message);
map.join(user,roomId);
sendMsg(buildCodeWithMsg(""+roomId+" "+message+" ",15));
returnMsg(buildCodeWithMsg("你进入了创建的房间:"+map.getRoom(roomId).getName(),5));
returnMsg(buildCodeWithMsg(getMembersInRoom(),21));
break;
case"setname":
//setnameforuser
//code=16,告诉房间里的其他人,你改了昵称
user.setName(message);
sendRoomMsg(buildCodeWithMsg(""+user.getId()+" "+message+" ",16));
break;
default:
//returnMsg("somethingunknown");
System.out.println("notvalidmessagefromuser"+user.getId());
break;
}
}
}
/**
*获得该用户房间中的所有用户列表,并构造成一定格式的消息返回
*@return
*/
privateStringgetMembersInRoom(){
/*先从room列表获得该用户的room*/
Roomroom=map.getRoom(roomId);
StringBufferstringBuffer=newStringBuffer();
if(room!=null){
/*获得房间中所有的用户的列表,然后构造成一定的格式发送回去*/
ArrayListusers=room.getUsers();
for(Usereach:users){
stringBuffer.append(""+each.getName()+
" "+each.getId()+" ");
}
}
returnstringBuffer.toString();
}
/**
*获得所有房间的列表,并构造成一定的格式
*@return
*/
privateStringgetRoomsList(){
String[][]strings=map.listRooms();
StringBuffersb=newStringBuffer();
for(inti=0;i"+strings[i][1]+
" "+strings[i][0]+" ");
}
returnsb.toString();
}
/**
*构造成一个统一的消息格式
*@parammsg
*@paramcode
*@return
*/
privateStringbuildCodeWithMsg(Stringmsg,intcode){
return""+code+""+msg+" \n";
}
/**
*这个是群发消息:全体用户,code>10
*@parammsg
*/
privatevoidsendMsg(Stringmsg){
//System.out.println("InsendMsg()");
/*取出用户列表中的每一个用户来发送消息*/
for(Usereach:userList){
try{
pw=each.getPw();
pw.println(msg);
pw.flush();
System.out.println(msg);
}catch(Exceptione){
System.out.println("exceptioninsendMsg()");
}
}
}
/**
*只对同一房间的用户发:code>10
*@parammsg
*/
privatevoidsendRoomMsg(Stringmsg){
/*先获得该用户的房间号,然后往该房间发送消息*/
Roomroom=map.getRoom(roomId);
if(room!=null){
ArrayListusers=room.getUsers();
for(Usereach:users){
pw=each.getPw();
pw.println(msg);
pw.flush();
}
}
}
/**
*向房间中除了该用户自己,发送消息
*@parammsg
*/
privatevoidsendRoomMsgExceptSelf(Stringmsg){
Roomroom=map.getRoom(roomId);
if(room!=null){
ArrayListusers=room.getUsers();
for(Usereach:users){
if(each.getId()!=user.getId()){
pw=each.getPw();
pw.println(msg);
pw.flush();
}
}
}
}
/**
*对于client的来信,返回一个结果,code<10
*@parammsg
*/
privatevoidreturnMsg(Stringmsg){
try{
pw=user.getPw();
pw.println(msg);
pw.flush();
}catch(Exceptione){
System.out.println("exceptioninreturnMsg()");
}
}
/**
*移除该用户,并向房间中其他用户发送该用户已经退出的消息
*如果房间中没人了,那么就更新房间列表给所有用户
*@paramuser
*/
privatevoidremove(Useruser){
if(roomId!=-1){
intflag=map.esc(user,roomId);
sendRoomMsgExceptSelf(buildCodeWithMsg(""+user.getId(),12));
longoldRoomId=roomId;
roomId=-1;
if(flag==0){
sendMsg(buildCodeWithMsg(""+oldRoomId,13));
}
}
userList.remove(user);
}
}
客户端
Client
packageClient;
importjava.awt.BorderLayout;
importjava.awt.Color;
importjava.awt.Dimension;
importjava.awt.FlowLayout;
importjava.awt.Font;
importjava.awt.GridBagConstraints;
importjava.awt.GridBagLayout;
importjava.awt.Insets;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.io.PrintWriter;
importjava.net.Socket;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Set;
importjava.util.regex.Matcher;
importjava.util.regex.Pattern;
importjavax.swing.DefaultListModel;
importjavax.swing.Icon;
importjavax.swing.ImageIcon;
importjavax.swing.JButton;
importjavax.swing.JFrame;
importjavax.swing.JLabel;
importjavax.swing.JList;
importjavax.swing.JOptionPane;
importjavax.swing.JPanel;
importjavax.swing.JScrollBar;
importjavax.swing.JScrollPane;
importjavax.swing.JTextField;
importjavax.swing.JTextPane;
importjavax.swing.UIManager;
importjavax.swing.UnsupportedLookAndFeelException;
importjavax.swing.text.BadLocationException;
importjavax.swing.text.SimpleAttributeSet;
importjavax.swing.text.Style;
importjavax.swing.text.StyleConstants;
importjavax.swing.text.StyledDocument;
/**
*
*@authorlannooo
*
*/
publicclassClientimplementsActionListener{
privateJFrameframe;
privateSocketsocket;
privateBufferedReaderbr;
privatePrintWriterpw;
privateStringname;
privateHashMaprooms_map;
privateHashMapusers_map;
privateJTextFieldhost_textfield;
privateJTextFieldport_textfield;
privateJTextFieldtext_field;
privateJTextFieldname_textfiled;
privateJLabelrooms_label;
privateJLabelusers_label;
privateJListroomlist;
privateJListuserlist;
privateJTextPanemsgArea;
privateJScrollPanetextScrollPane;
privateJScrollBarvertical;
DefaultListModelrooms_model;
DefaultListModelusers_model;
/*
*构造函数
*该客户端对象维护两个map,房间的hashmap和房间中用户的hashmap
*作为列表组件的数据模型
*/
publicClient(){
rooms_map=newHashMap<>();
users_map=newHashMap<>();
initialize();
}
/**
*连接服务端,指定host和port
*@paramhost
*@paramport
*@return
*/
publicbooleanconnect(Stringhost,intport){
try{
socket=newSocket(host,port);
System.out.println("Connectedtoserver!"+socket.getRemoteSocketAddress());
br=newBufferedReader(newInputStreamReader(System.in));
pw=newPrintWriter(socket.getOutputStream());
/*
*创建一个接受和解析服务器消息的线程
*传入当前客户端对象的指针,作为句柄调用相应的处理函数
*/
ClientThreadthread=newClientThread(socket,this);
thread.start();
returntrue;
}catch(IOExceptione){
System.out.println("Servererror");
JOptionPane.showMessageDialog(frame,"服务器无法连接!");
returnfalse;
}
}
/*当前进程作为只发送消息的线程,从命令行中获取输入*/
//publicvoidsendMsg(){
//Stringmsg;
//try{
//while(true){
//msg=br.readLine();
//pw.println(msg);
//pw.flush();
//}
//}catch(IOExceptione){
//System.out.println("errorwhenreadmsgandtosend.");
//}
//}
/**
*发给服务器的消息,先经过一定的格式构造再发送
*@parammsg
*@paramcode
*/
publicvoidsendMsg(Stringmsg,Stringcode){
try{
pw.println(""+code+""+msg+" ");
pw.flush();
}catch(Exceptione){
//一般是没有连接的问题
System.out.println("errorinsendMsg()");
JOptionPane.showMessageDialog(frame,"请先连接服务器!");
}
}
/**
*窗口初始化
*/
privatevoidinitialize(){
/*设置窗口的UI风格和字体*/
setUIStyle();
setUIFont();
JFrameframe=newJFrame("ChatOnline");
JPanelpanel=newJPanel();/*主要的panel,上层放置连接区,下层放置消息区,
中间是消息面板,左边是room列表,右边是当前room的用户列表*/
JPanelheadpanel=newJPanel();/*上层panel,用于放置连接区域相关的组件*/
JPanelfootpanel=newJPanel();/*下层panel,用于放置发送信息区域的组件*/
JPanelleftpanel=newJPanel();/*左边panel,用于放置房间列表和加入按钮*/
JPanelrightpanel=newJPanel();/*右边panel,用于放置房间内人的列表*/
/*最上层的布局,分中间,东南西北五个部分*/
BorderLayoutlayout=newBorderLayout();
/*格子布局,主要用来设置西、东、南三个部分的布局*/
GridBagLayoutgridBagLayout=newGridBagLayout();
/*主要设置北部的布局*/
FlowLayoutflowLayout=newFlowLayout();
/*设置初始窗口的一些性质*/
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(newDimension(130,0));
rightpanel.setPreferredSize(newDimension(130,0));
/*以下均是headpanel中的组件*/
host_textfield=newJTextField("127.0.0.1");
port_textfield=newJTextField("9999");
name_textfiled=newJTextField("匿名");
host_textfield.setPreferredSize(newDimension(100,25));
port_textfield.setPreferredSize(newDimension(70,25));
name_textfiled.setPreferredSize(newDimension(150,25));
JLabelhost_label=newJLabel("服务器IP");
JLabelport_label=newJLabel("端口");
JLabelname_label=newJLabel("昵称");
JButtonhead_connect=newJButton("连接");
//JButtonhead_change=newJButton("确认更改");
JButtonhead_create=newJButton("创建房间");
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中的组件*/
JButtonfoot_emoji=newJButton("表情");
JButtonfoot_send=newJButton("发送");
text_field=newJTextField();
footpanel.add(text_field,newGridBagConstraints(0,0,1,1,100,100,
GridBagConstraints.CENTER,GridBagConstraints.BOTH,newInsets(0,0,0,0),0,0));
footpanel.add(foot_emoji,newGridBagConstraints(1,0,1,1,1.0,1.0,
GridBagConstraints.CENTER,GridBagConstraints.BOTH,newInsets(0,0,0,0),0,0));
footpanel.add(foot_send,newGridBagConstraints(2,0,1,1,1.0,1.0,
GridBagConstraints.CENTER,GridBagConstraints.BOTH,newInsets(0,0,0,0),0,0));
/*两边的格子中的组件*/
rooms_label=newJLabel("当前房间数:0");
users_label=newJLabel("房间内人数:0");
JButtonjoin_button=newJButton("加入房间");
JButtonesc_button=newJButton("退出房间");
rooms_model=newDefaultListModel<>();
users_model=newDefaultListModel<>();
//rooms_model.addElement("房间1");
//rooms_model.addElement("房间2");
//rooms_model.addElement("房间3");
//Stringfangjian="房间1";
//rooms_map.put(fangjian,1);
roomlist=newJList<>(rooms_model);
userlist=newJList<>(users_model);
JScrollPaneroomListPane=newJScrollPane(roomlist);
JScrollPaneuserListPane=newJScrollPane(userlist);
leftpanel.add(rooms_label,newGridBagConstraints(0,0,1,1,1,1,
GridBagConstraints.CENTER,GridBagConstraints.BOTH,newInsets(0,0,0,0),0,0));
leftpanel.add(join_button,newGridBagConstraints(0,1,1,1,1,1,
GridBagConstraints.CENTER,GridBagConstraints.BOTH,newInsets(0,0,0,0),0,0));
leftpanel.add(esc_button,newGridBagConstraints(0,2,1,1,1,1,
GridBagConstraints.CENTER,GridBagConstraints.BOTH,newInsets(0,0,0,0),0,0));
leftpanel.add(roomListPane,newGridBagConstraints(0,3,1,1,100,100,
GridBagConstraints.CENTER,GridBagConstraints.BOTH,newInsets(0,0,0,0),0,0));
rightpanel.add(users_label,newGridBagConstraints(0,0,1,1,1,1,
GridBagConstraints.CENTER,GridBagConstraints.BOTH,newInsets(0,0,0,0),0,0));
rightpanel.add(userListPane,newGridBagConstraints(0,1,1,1,100,100,
GridBagConstraints.CENTER,GridBagConstraints.BOTH,newInsets(0,0,0,0),0,0));
/*中间的文本区组件*/
msgArea=newJTextPane();
msgArea.setEditable(false);
textScrollPane=newJScrollPane();
textScrollPane.setViewportView(msgArea);
vertical=newJScrollBar(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
publicvoidactionPerformed(ActionEvente){
Stringcmd=e.getActionCommand();
switch(cmd){
case"连接":/*点击连接按钮*/
Stringstrhost=host_textfield.getText();
Stringstrport=port_textfield.getText();
connect(strhost,Integer.parseInt(strport));
StringnameSeted=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"确认更改":
//Stringstrname=name_textfiled.getText();
//name=strname;
//sendMsg(strname,"setname");
//break;
case"加入房间":/*选择房间后,点击加入房间按钮*/
Stringselected=roomlist.getSelectedValue();
if(rooms_map.containsKey(selected)){
sendMsg(""+rooms_map.get(selected),"join");
}
break;
case"退出房间":/*点击退出房间的按钮*/
sendMsg("","esc");
break;
case"发送":/*点击发送消息的按钮*/
Stringtext=text_field.getText();
text_field.setText("");
sendMsg(text,"message");
break;
case"表情":/*发送表情,新建一个表情窗口,并直接在表情窗口中处理消息发送*/
IconDialogdialog=newIconDialog(frame,this);
break;
case"创建房间":/*点击创建房间的按钮,弹出提示框数据房间名称*/
Stringstring=JOptionPane.showInputDialog("请输入你的房间名称");
if(string==null||string.equals("")){
string=name+(int)(Math.random()*10000)+"的房间";
}
sendMsg(string,"create");
break;
default:
break;
}
}
/*很多辅助和clientThread互动的*/
/**
*加入用户,通过正则表达式,匹配消息内容中的用户信息
*@paramcontent
*/
publicvoidaddUser(Stringcontent){
if(content.length()>0){
Patternpattern=Pattern.compile("(.*) (.*) ");
Matchermatcher=pattern.matcher(content);
if(matcher.find()){
/*
*获得用户的name和id
*加入用户列表
*在消息区显示系统提示
*/
Stringname=matcher.group(1);
Stringid=matcher.group(2);
insertUser(Integer.parseInt(id),name);
insertMessage(textScrollPane,msgArea,null,"系统:",name+"加入了聊天室");
}
}
users_label.setText("房间内人数:"+users_map.size());/*更新房间内的人数*/
}
/**
*删除用户
*@paramcontent
*/
publicvoiddelUser(Stringcontent){
if(content.length()>0){
intid=Integer.parseInt(content);
/*
*从维护的用户map中取得所有的用户名字,然后去遍历匹配的用户
*匹配到的用户名字从相应的数据模型中移除
*并从map中移除,并在消息框中提示系统消息
*/
Setset=users_map.keySet();
Iteratoriter=set.iterator();
Stringname=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());
}
/**
*更新用户信息
*@paramcontent
*/
publicvoidupdateUser(Stringcontent){
if(content.length()>0){
Patternpattern=Pattern.compile("(.*) (.*) ");
Matchermatcher=pattern.matcher(content);
if(matcher.find()){
Stringid=matcher.group(1);
Stringname=matcher.group(2);
insertUser(Integer.parseInt(id),name);
}
}
}
/**
*列出所有用户
*@paramcontent
*/
publicvoidlistUsers(Stringcontent){
Stringname=null;
Stringid=null;
Patternrough_pattern=null;
Matcherrough_matcher=null;
Patterndetail_pattern=null;
/*
*先用正则表达式匹配用户信息
*然后插入数据模型中
*并更新用户数据模型中的条目
*/
if(content.length()>0){
rough_pattern=Pattern.compile("(.*?) ");
rough_matcher=rough_pattern.matcher(content);
while(rough_matcher.find()){
Stringdetail=rough_matcher.group(1);
detail_pattern=Pattern.compile("(.*) (.*) ");
Matcherdetail_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中显示消息
*@paramcontent
*/
publicvoidupdateTextArea(Stringcontent){
insertMessage(textScrollPane,msgArea,null,"系统:",content);
}
/**
*在textarea中显示其他用户的消息
*先用正则匹配,再显示消息
*其中还需要匹配emoji表情的编号
*@paramcontent
*/
publicvoidupdateTextAreaFromUser(Stringcontent){
if(content.length()>0){
Patternpattern=Pattern.compile("(.*) (.*) ");
Matchermatcher=pattern.matcher(content);
if(matcher.find()){
Stringfrom=matcher.group(1);
Stringsmsg=matcher.group(2);
StringfromName=getUserName(from);
if(fromName.equals(name))
fromName="你";
if(smsg.startsWith("")){
StringemojiCode=smsg.substring(7,smsg.length()-8);
//System.out.println(emojiCode);
insertMessage(textScrollPane,msgArea,emojiCode,fromName+"说:",null);
return;
}
insertMessage(textScrollPane,msgArea,null,fromName+"说:",smsg);
}
}
}
/**
*显示退出的结果
*@paramcontent
*/
publicvoidshowEscDialog(Stringcontent){
JOptionPane.showMessageDialog(frame,content);
/*清除消息区内容,清除用户数据模型内容和用户map内容,更新房间内人数*/
msgArea.setText("");
users_model.clear();
users_map.clear();
users_label.setText("房间内人数:0");
}
/**
*新增一个room
*@paramcontent
*/
publicvoidaddRoom(Stringcontent){
if(content.length()>0){
Patternpattern=Pattern.compile("(.*) (.*) ");
Matchermatcher=pattern.matcher(content);
if(matcher.find()){
Stringrid=matcher.group(1);
Stringrname=matcher.group(2);
insertRoom(Integer.parseInt(rid),rname);
}
}
rooms_label.setText("当前房间数:"+rooms_map.size());
}
/**
*删除一个room
*@paramcontent
*/
publicvoiddelRoom(Stringcontent){
if(content.length()>0){
intdelRoomId=Integer.parseInt(content);
Setset=rooms_map.keySet();
Iteratoriter=set.iterator();
Stringrname=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
*@paramcontent
*/
publicvoidlistRooms(Stringcontent){
Stringrname=null;
Stringrid=null;
Patternrough_pattern=null;
Matcherrough_matcher=null;
Patterndetail_pattern=null;
if(content.length()>0){
rough_pattern=Pattern.compile("(.*?) ");
rough_matcher=rough_pattern.matcher(content);
while(rough_matcher.find()){
Stringdetail=rough_matcher.group(1);
detail_pattern=Pattern.compile("(.*) (.*) ");
Matcherdetail_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
*@paramrid
*@paramrname
*/
privatevoidinsertRoom(Integerrid,Stringrname){
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
*@paramid
*@paramname
*/
privatevoidinsertUser(Integerid,Stringname){
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());
}
/**
*获得用户的姓名
*@paramstrId
*@return
*/
privateStringgetUserName(StringstrId){
intuid=Integer.parseInt(strId);
Setset=users_map.keySet();
Iteratoriterator=set.iterator();
Stringcur=null;
while(iterator.hasNext()){
cur=iterator.next();
if(users_map.get(cur)==uid){
returncur;
}
}
return"";
}
/**
*获得用户所在房间的名称
*@paramstrId
*@return
*/
privateStringgetRoomName(StringstrId){
intrid=Integer.parseInt(strId);
Setset=rooms_map.keySet();
Iteratoriterator=set.iterator();
Stringcur=null;
while(iterator.hasNext()){
cur=iterator.next();
if(rooms_map.get(cur)==rid){
returncur;
}
}
return"";
}
/**
*打印一条消息,如果有图片就打印图片,否则打印content
*@paramscrollPane
*@paramtextPane
*@paramicon_code
*@paramtitle
*@paramcontent
*/
privatevoidinsertMessage(JScrollPanescrollPane,JTextPanetextPane,
Stringicon_code,Stringtitle,Stringcontent){
StyledDocumentdocument=textPane.getStyledDocument();/*获取textpane中的文本*/
/*设置标题的属性*/
SimpleAttributeSettitle_attr=newSimpleAttributeSet();
StyleConstants.setBold(title_attr,true);
StyleConstants.setForeground(title_attr,Color.BLUE);
/*设置正文的属性*/
SimpleAttributeSetcontent_attr=newSimpleAttributeSet();
StyleConstants.setBold(content_attr,false);
StyleConstants.setForeground(content_attr,Color.BLACK);
Stylestyle=null;
if(icon_code!=null){
Iconicon=newImageIcon("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(BadLocationExceptionex){
System.out.println("Badlocationexception");
}
/*设置滑动条到最后*/
vertical.setValue(vertical.getMaximum());
}
/**
*设置需要美化字体的组件
*/
publicstaticvoidsetUIFont()
{
Fontf=newFont("微软雅黑",Font.PLAIN,14);
Stringnames[]={"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(Stringitem:names){
UIManager.put(item+".font",f);
}
}
/**
*设置UI风格为当前系统的风格
*/
publicstaticvoidsetUIStyle(){
StringlookAndFeel=UIManager.getSystemLookAndFeelClassName();
try{
UIManager.setLookAndFeel(lookAndFeel);
}catch(ClassNotFoundExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}catch(InstantiationExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}catch(IllegalAccessExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}catch(UnsupportedLookAndFeelExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
/**
*测试用的main函数
*@paramargs
*/
publicstaticvoidmain(String[]args){
Clientclient=newClient();
}
}
ClientThread
packageClient;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.io.PrintWriter;
importjava.net.Socket;
importjava.util.regex.Matcher;
importjava.util.regex.Pattern;
/**
*
*@authorlannooo
*
*/
publicclassClientThreadextendsThread{
privateSocketsocket;
privateClientclient;
privateBufferedReaderbr;
privatePrintWriterpw;
/**
*从过主线程传入的socket和client对象来构造
*@paramsocket
*@paramclient
*/
publicClientThread(Socketsocket,Clientclient){
this.client=client;
this.socket=socket;
try{
br=newBufferedReader(newInputStreamReader(socket.getInputStream()));
}catch(IOExceptione){
System.out.println("cannotgetinputstreamfromsocket.");
}
}
/**
*不断的读数据并处理
*调用主线程的方法来处理:client.method();
*/
publicvoidrun(){
try{
br=newBufferedReader(newInputStreamReader(socket.getInputStream()));
while(true){
Stringmsg=br.readLine();
parseMessage(msg);
}
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*处理从服务器收到的消息
*@parammessage
*/
publicvoidparseMessage(Stringmessage){
Stringcode=null;
Stringmsg=null;
/*
*先用正则表达式匹配code码和msg内容
*/
if(message.length()>0){
Patternpattern=Pattern.compile("(.*)");
Matchermatcher=pattern.matcher(message);
if(matcher.find()){
code=matcher.group(1);
}
pattern=Pattern.compile("(.*) ");
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(选择表情界面)
packageClient;
importjava.awt.Container;
importjava.awt.Dialog;
importjava.awt.FlowLayout;
importjava.awt.GridLayout;
importjava.awt.Image;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
importjavax.swing.ImageIcon;
importjavax.swing.JButton;
importjavax.swing.JDialog;
importjavax.swing.JFrame;
/**
*
*@authorlannooo
*
*/
publicclassIconDialogimplementsActionListener{
privateJDialogdialog;
privateClientclient;
/**
*通过frame和客户端对象来构造
*@paramframe
*@paramclient
*/
publicIconDialog(JFrameframe,Clientclient){
this.client=client;
dialog=newJDialog(frame,"请选择表情",true);
/*16个表情*/
JButton[]icon_button=newJButton[16];
ImageIcon[]icons=newImageIcon[16];
/*获得弹出窗口的容器,设置布局*/
ContainerdialogPane=dialog.getContentPane();
dialogPane.setLayout(newGridLayout(0,4));
/*加入表情*/
for(inti=1;i<=15;i++){
icons[i]=newImageIcon("icon/"+i+".png");
icons[i].setImage(icons[i].getImage().getScaledInstance(50,50,Image.SCALE_DEFAULT));
icon_button[i]=newJButton(""+i,icons[i]);
icon_button[i].addActionListener(this);
dialogPane.add(icon_button[i]);
}
dialog.setBounds(200,266,266,280);
dialog.show();
}
@Override
publicvoidactionPerformed(ActionEvente){
/*构造emoji结构的消息发送*/
Stringcmd=e.getActionCommand();
System.out.println(cmd);
dialog.dispose();
client.sendMsg(""+cmd+" ","message");
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。