該類主要實現底層的網絡通信功能 在該類中提供了壹個broadCast方法 該方法使用MulticastSocket將指定字符串廣播到所有客戶端 還提供了sendSingle方法 該方法使用DatagramSocket將指定字符串發送到指定SocketAddress 如程序中前兩行粗體字代碼所示 除此之外 該類裏還提供了 個內部線程類 ReadSingle和ReadBroad 這兩個線程類采用循環不斷讀取DatagramSocket和MulticastSocket中的數據 如果讀到的信息是廣播來的在線信息 則保持該用戶在線 如果讀到的是用戶的聊天信息 則直接將該信息顯示出來
在該類中用到了本程序的壹個主類 LanChat 該類使用DefaultListModel來維護用戶列表 該類裏的每個列表項就是壹個UserInfo 該類還提供了壹個ImageCellRenderer 該類用於將列表項繪制出用戶圖標和用戶名字
程序清單 codes/ / /LanChat/LanChat java
public class LanChat extends JFrame
{
private DefaultListModel listModel = new DefaultListModel()
//定義壹個JList對象
private JList friendsList = new JList(listModel)
//定義壹個用於格式化日期的格式器
private DateFormat formatter = DateFormat getDateTimeInstance()
public LanChat()
{
super( 局域網聊天 )
//設置該JList使用ImageCellRenderer作為單元格繪制器
friendsList setCellRenderer(new ImageCellRenderer())
listModel addElement(new UserInfo( all 所有人 null ))
friendsList addMouseListener(new ChangeMusicListener())
add(new JScrollPane(friendsList))
setDefaultCloseOperation(JFrame EXIT_ON_CLOSE)
setBounds( )
}
//向用戶列表中添加用戶
public void addUser(UserInfo user)
{
listModel addElement(user)
}
//從用戶列表中刪除用戶
public void removeUser(int pos)
{
listModel removeElementAt(pos)
}
//根據地址來查詢用戶
public UserInfo getUserBySocketAddress(SocketAddress address)
{
for (int i = ; i < getUserNum() ; i++)
{
UserInfo user = getUser(i)
if (user getAddress() != null &&
user getAddress() equals(address))
{
return user;
}
}
return null;
}
// 下面兩個方法是對ListModel的包裝
//獲取該聊天窗口的用戶數量
public int getUserNum()
{
return listModel size()
}
//獲取指定位置的用戶
public UserInfo getUser(int pos)
{
return (UserInfo)listModel elementAt(pos)
}
//實現JList上的鼠標雙擊監聽器
class ChangeMusicListener extends MouseAdapter
{
public void mouseClicked(MouseEvent e)
{
//如果鼠標的擊鍵次數大於
if (e getClickCount() >= )
{
//取出鼠標雙擊時選中的列表項
UserInfo user = (UserInfo)friendsList getSelectedValue()
//如果該列表項對應用戶的交談窗口為null
if (user getChatFrame() == null)
{
//為該用戶創建壹個交談窗口 並讓該用戶引用該窗口
user setChatFrame(new ChatFrame(null user))
}
//如果該用戶的窗口沒有顯示 則讓該用戶的窗口顯示出來
if (!user getChatFrame() isShowing())
{
user getChatFrame() setVisible(true)
}
}
}
}
/**
* 處理網絡數據報 該方法將根據聊天信息得到聊天者
* 並將信息顯示在聊天對話框中
* @param packet 需要處理的數據報
* @param single 該信息是否為私聊信息
*/
public void processMsg(DatagramPacket packet boolean single)
{
//獲取該發送該數據報的SocketAddress
InetSocketAddress srcAddress = (InetSocketAddress)packet getSocket
Address()
//如果是私聊信息 則該Packet獲取的是DatagramSocket的地址 將端口減 才是
//對應的MulticastSocket的地址
if (single)
{
srcAddress = new InetSocketAddress(srcAddress getHostName()
srcAddress getPort() )
}
UserInfo srcUser = getUserBySocketAddress(srcAddress)
if (srcUser != null)
{
//確定消息將要顯示到哪個用戶對應窗口上
UserInfo alertUser = single ? srcUser : getUser( )
//如果該用戶對應的窗口為空 顯示該窗口
if (alertUser getChatFrame() == null)
{
alertUser setChatFrame(new ChatFrame(null alertUser))
}
//定義添加的提示信息
String tipMsg = single ? 對您說 : 對大家說 ;
//顯示提示信息
alertUser getChatFrame() addString(srcUser getName() + tipMsg
+ ……( + formatter format(new Date()) + )\n
+ new String(packet getData() packet getLength()) + \n )
if (!alertUser getChatFrame() isShowing())
{
alertUser getChatFrame() 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/ + userInfo getIcon() + gif )
name = userInfo getName()
background = isSelected ? list getSelectionBackground() : list getBack
ground()
foreground = isSelected ? list getSelectionForeground() : list
getForeground()
//返回該JPanel對象作為單元格繪制器
return this;
}
//重寫paintComponent方法 改變JPanel的外觀
public void paintComponent(Graphics g)
{
int imageWidth = icon getImage() getWidth(null)
int imageHeight = icon getImage() getHeight(null)
g setColor(background)
g fillRect( getWidth() getHeight())
g setColor(foreground)
//繪制好友圖標
g drawImage(icon getImage() getWidth() / imageWidth / null)
g setFont(new Font( SansSerif Font BOLD ))
//繪制好友用戶名
g drawString(name getWidth() / name length() * imageHeight + )
}
//通過該方法來設置該ImageCellRenderer的最佳大小
public Dimension getPreferredSize()
{
return new Dimension( )
}
}
上面類中提供的addUser和removeUser方法用於暴露給通信類ComUtil使用 用於向用戶列表中添加 刪除用戶 除此之外 該類還提供了壹個processMsg方法 該方法用於處理網絡中讀取的數據報 將數據報中的內容取出 並顯示在特定的窗口中
上面講解的只是本程序的關鍵類 本程序還涉及YeekuProtocol ChatFrame LoginFrame等類 由於篇幅關系 此處不再給出這些類的源代碼 讀者可以參考codes/ / /LanTalk路徑下的源代碼
? 返回目錄 瘋狂Java講義
? 編輯推薦
? Java程序性能優化 讓妳的Java程序更快 更穩定
? 新手學Java 編程
lishixinzhi/Article/program/Java/hx/201311/27255