该类主要实现底层的网络通信功能在该类中提供了一个broadCast方法该方法使用MulticastSocket将指定字符串广播到所有客户端还提供了sendSingle方法该方法使用DatagramSocket将指定字符串发送到指定SocketAddress如程序中前两行粗体字代码所示除此之外该类里还提供了个内部线程类ReadSingle和ReadBroad这两个线程类采用循环不断读取DatagramSocket和MulticastSocket中的数据如果读到的信息是广播来的在线信息则保持该用户在线如果读到的是用户的聊天信息则直接将该信息显示出来
在该类中用到了本程序的一个主类LanChat该类使用DefaultListModel来维护用户列表该类里的每个列表项就是一个UserInfo该类还提供了一个ImageCellRenderer该类用于将列表项绘制出用户图标和用户名字
程序清单codes///LanChat/LanChatjava
public class LanChat extends JFrame
{
private DefaultListModel listModel = new DefaultListModel()
//定义一个JList对象
private JList friendsList = new JList(listModel)
//定义一个用于格式化日期的格式器
private DateFormat formatter = DateFormatgetDateTimeInstance()
public LanChat()
{
super(局域网聊天)
//设置该JList使用ImageCellRenderer作为单元格绘制器
friendsListsetCellRenderer(new ImageCellRenderer())
listModeladdElement(new UserInfo(all 所有人 null ))
friendsListaddMouseListener(new ChangeMusicListener())
add(new JScrollPane(friendsList))
setDefaultCloseOperation(JFrameEXIT_ON_CLOSE)
setBounds( )
}
//向用户列表中添加用户
public void addUser(UserInfo user)
{
listModeladdElement(user)
}
//从用户列表中删除用户
public void removeUser(int pos)
{
listModelremoveElementAt(pos)
}
//根据地址来查询用户
public UserInfo getUserBySocketAddress(SocketAddress address)
{
for (int i = ; i < getUserNum() ; i++)
{
UserInfo user = getUser(i)
if (usergetAddress() != null &&
usergetAddress()equals(address))
{
return user;
}
}
return null;
}
//下面两个方法是对ListModel的包装
//获取该聊天窗口的用户数量
public int getUserNum()
{
return listModelsize()
}
//获取指定位置的用户
public UserInfo getUser(int pos)
{
return (UserInfo)listModelelementAt(pos)
}
//实现JList上的鼠标双击监听器
class ChangeMusicListener extends MouseAdapter
{
public void mouseClicked(MouseEvent e)
{
//如果鼠标的击键次数大于
if (egetClickCount() >= )
{
//取出鼠标双击时选中的列表项
UserInfo user = (UserInfo)friendsListgetSelectedValue()
//如果该列表项对应用户的交谈窗口为null
if (usergetChatFrame() == null)
{
//为该用户创建一个交谈窗口并让该用户引用该窗口
usersetChatFrame(new ChatFrame(null user))
}
//如果该用户的窗口没有显示则让该用户的窗口显示出来
if (!usergetChatFrame()isShowing())
{
usergetChatFrame()setVisible(true)
}
}
}
}
/**
* 处理网络数据报该方法将根据聊天信息得到聊天者
* 并将信息显示在聊天对话框中
* @param packet 需要处理的数据报
* @param single 该信息是否为私聊信息
*/
public void processMsg(DatagramPacket packet boolean single)
{
//获取该发送该数据报的SocketAddress
InetSocketAddress srcAddress = (InetSocketAddress)packetgetSocket
Address()
//如果是私聊信息则该Packet获取的是DatagramSocket的地址将端口减才是
//对应的MulticastSocket的地址
if (single)
{
srcAddress = new InetSocketAddress(srcAddressgetHostName()
srcAddressgetPort() )
}
UserInfo srcUser = getUserBySocketAddress(srcAddress)
if (srcUser != null)
{
//确定消息将要显示到哪个用户对应窗口上
UserInfo alertUser = single ? srcUser : getUser()
//如果该用户对应的窗口为空显示该窗口
if (alertUsergetChatFrame() == null)
{
alertUsersetChatFrame(new ChatFrame(null alertUser))
}
//定义添加的提示信息
String tipMsg = single ? 对您说 : 对大家说;
//显示提示信息
alertUsergetChatFrame()addString(srcUsergetName() + tipMsg
+ ……( + formatterformat(new Date()) + )\n
+ new String(packetgetData() packetgetLength()) + \n)
if (!alertUsergetChatFrame()isShowing())
{
alertUsergetChatFrame()setVisible(true)
}
}
}
//主方法程序的入口
public static void main(String[] args)
{
LanChat lc = new LanChat()
new LoginFrame(lc 请输入用户名头像后登录)
}
}
//定义用于改变JList列表项外观的类
class ImageCellRenderer extends JPanel implements ListCellRenderer
{
private ImageIcon icon;
private String name;
//定义绘制单元格时的背景色
private Color background;
//定义绘制单元格时的前景色
private Color foreground;
public Component getListCellRendererComponent(JList list Object value int
index boolean isSelected boolean cellHasFocus)
{
UserInfo userInfo = (UserInfo)value;
icon = new ImageIcon(ico/ + userInfogetIcon() + gif)
name = userInfogetName()
background = isSelected ? listgetSelectionBackground() : listgetBack
ground()
foreground = isSelected ? listgetSelectionForeground() : list
getForeground()
//返回该JPanel对象作为单元格绘制器
return this;
}
//重写paintComponent方法改变JPanel的外观
public void paintComponent(Graphics g)
{
int imageWidth = icongetImage()getWidth(null)
int imageHeight = icongetImage()getHeight(null)
gsetColor(background)
gfillRect( getWidth() getHeight())
gsetColor(foreground)
//绘制好友图标
gdrawImage(icongetImage() getWidth() / imageWidth / null)
gsetFont(new Font(SansSerif FontBOLD ))
//绘制好友用户名
gdrawString(name getWidth() / namelength() * imageHeight + )
}
//通过该方法来设置该ImageCellRenderer的最佳大小
public Dimension getPreferredSize()
{
return new Dimension( )
}
}
上面类中提供的addUser和removeUser方法用于暴露给通信类ComUtil使用用于向用户列表中添加删除用户除此之外该类还提供了一个processMsg方法该方法用于处理网络中读取的数据报将数据报中的内容取出并显示在特定的窗口中
上面讲解的只是本程序的关键类本程序还涉及YeekuProtocolChatFrameLoginFrame等类由于篇幅关系此处不再给出这些类的源代码读者可以参考codes///LanTalk路径下的源代码
返回目录疯狂Java讲义
编辑推荐
Java程序性能优化让你的Java程序更快更稳定
新手学Java 编程
Java程序设计培训视频教程