源代码下载链接:http://download.csdn.net/detail/sky453589103/9514686
如果有什么问题,欢迎留言。
主窗口用的是JList控件,在显示了登陆的跟人信息之后,接下来就是好友的列表。
为了方便以后拓展 ,我把好友的信息封装在FriendInformation中,FriendInformation类的定义也很简单的,都能看懂。
下面来逐步分析一下MainWin类:
MainWin中比较重要的是事件的监听:
好友列表中的右键菜单的监听:
JMenuItem item = new JMenuItem("remove"); item.addActionListener(new ActionListener () { @Override public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub RequestMessage request = new RequestMessage(); request.setFrom(username); request.setTo(friendJList.getSelectedValue().getName()); request.setCommand("remove a friend"); try { PrintStream out = new PrintStream(getServer().getOutputStream()); out.print(request.Format()); } catch (IOException e) { } } }); friendListPopupMenu.add(item);
在因为我的右键菜单中只有一个选项,因此写的很简单,但是用来举例,完全足够了。当选中了这个选项之后,客户端会生成删除还有的请求报文发送给服务器端,服务器端hi执行这个动作,如果删除成功,就返回删除了之后的好友列表。
好友列表的选定模式应该是单选的,通过下面的函数来设定:
this.friendJList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
好友列表的监听操作:
this.friendJList.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent e) { // if mouse's right key click, the line will be selected. if (e.getButton() == 3) { friendJList.setSelectedIndex(friendJList.locationToIndex(e.getPoint())); } // getButton function's return value has three value. // 1 represent mouse's left key. // 3 represent mouse's right key. if (e.getButton() == 1 && e.getClickCount() >= 2) { // index of being double clicked line // int index = friendJList.getSelectedIndex(); FriendInformation f = (FriendInformation) friendJList.getSelectedValue(); // FriendInformation f = friendList.get(index); if (f.getStatus().equals("on")) { AddChatWin(f.getName()); } else { JOptionPane.showMessageDialog(null, f.getName() + " is offline!", "message", JOptionPane.INFORMATION_MESSAGE); } friendJList.clearSelection(); } else if (e.getButton() == 3 && friendJList.getSelectedIndex() >= 0) { friendListPopupMenu.show(e.getComponent(), e.getX(), e.getY()); } } });
省略了的后面的三个函数可以不看,都是空的。
if (e.getButton() == 3) { friendJList.setSelectedIndex(friendJList.locationToIndex(e.getPoint())); }
getButton函数会有三个返回值,1代表左键,2代表中键,3代表右键。
这段代码,实现的是,如果是右击一行,这一行也会被选中。
接下来判断的
1.是不是左键双击了某一行。如果是,就创建响应的聊天窗口,如果聊天窗口存在就将它显示出来。
2.是不是右键单击了某一行,如果是,就弹出右键菜单。
自定义JList的渲染模式, 需要调用setCellRenderer函数才会生效:
class FriendJListRenderer extends JPanel implements ListCellRenderer<FriendInformation> { /** * */ private static final long serialVersionUID = 1L; private JLabel lbIcon = new JLabel(); private JLabel lbName = new JLabel(); private JLabel lbStatus = new JLabel(); public FriendJListRenderer() { setLayout(new BorderLayout(5, 5)); JPanel panelText = new JPanel(new GridLayout(0, 1)); panelText.add(lbName); panelText.add(lbStatus); add(lbIcon, BorderLayout.WEST); add(panelText, BorderLayout.CENTER); } @Override public Component getListCellRendererComponent(JList<? extends FriendInformation> list, FriendInformation friend, int index, boolean isSelected, boolean cellHasFocus) { ImageIcon icon = new ImageIcon(getClass().getResource("/SimpleChat/Mushroom2.png")); lbIcon.setIcon(icon); // lbIcon.setText("this is a icon \r\n but not show by List\r\n // error?"); lbName.setText(friend.getName()); lbStatus.setText(friend.getStatus()); lbStatus.setForeground(Color.blue); // set Opaque to change background color of JLabel lbName.setOpaque(true); lbStatus.setOpaque(true); lbIcon.setOpaque(true); // when select item if (isSelected) { lbName.setBackground(list.getSelectionBackground()); lbStatus.setBackground(list.getSelectionBackground()); lbIcon.setBackground(list.getSelectionBackground()); setBackground(list.getSelectionBackground()); } else { // when don't select lbName.setBackground(list.getBackground()); lbStatus.setBackground(list.getBackground()); lbIcon.setBackground(list.getBackground()); setBackground(list.getBackground()); } return this; } }
添加好友的按钮的事件监听:
在按下添加好友的按钮之后会先出现一个带输入框的窗口,在输入了要添加的好友的名字之后,就可以执行添加好友的操作。
addFriendButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { // String inputValue = JOptionPane.showInputDialog(this, "Please // input a name"); String inputValue = JOptionPane.showInputDialog(null, "Please input a name", "add a new friend", JOptionPane.CLOSED_OPTION); if (!inputValue.equals("")) { RequestMessage request = new RequestMessage(); request.setFrom(username); request.setTo(inputValue); request.setCommand("add a friend"); try { PrintStream out = new PrintStream(getServer().getOutputStream()); out.print(request.Format()); } catch (IOException e) { } } } });
需要注意的是,在登陆操作之后,所有的来自服务器的响应的消息都会在startn函数中接收,然后根据响应消息的code和description做出响应的处理。因为篇幅原因,这不在展开了。
而聊天窗口中,负责的只是消息文本的添加和发送,接收信息的四级操作是在主窗口中进行的。因为在这样做可以避免同时有多个流在监听输入,而造成混乱。
聊天窗口在接收到对方的信息的时候,会加上当前的系统时间,通过下面代码实现:
public void addMessage(String from, String content) { Date date = new Date(); messageTextArea.setText( messageTextArea.getText() + "\r\n" + from + " " + dateFormat.format(date) + "\r\n" + content); }
通过Date类来获取当前的系统时间,并格式化消息,添加到消息文本框中。