简易聊天程序教程(六)主窗口和聊天窗口

源代码下载链接: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类来获取当前的系统时间,并格式化消息,添加到消息文本框中。

时间: 2024-08-20 02:47:02

简易聊天程序教程(六)主窗口和聊天窗口的相关文章

简易聊天程序教程(四)客户端基本功能

源代码下载链接:http://download.csdn.net/detail/sky453589103/9514686 如果有什么问题,欢迎留言. 客户端的基本功能是根据服务器给出的接口逐步来实现的.客户端的设计流程是清晰的.简化的思考流程如下图所示: 当然,实现的时候就要考虑比较多的细节,比如在注册的时候,注册失败怎么办,登陆的时候,账号密码不匹配怎么办.但总的流程就是这样子的. 从上面的流程可以看出了,客户端的窗口模块分下面几个(附上动作的解析): 1 登陆窗口模块: 登陆窗口需要提供两个

简易聊天程序教程(一)自定义异常和消息格式

源代码下载链接:http://download.csdn.net/detail/sky453589103/9514686 如果有什么问题,欢迎留言. 自定义异常的目的是为了更好的表示出错的原因,能够针对不同的异常执行不同的处理. 异常的自定义是简单的,只是简单的继承了Exception类.下面给出所有聊天程序的异常类的基类的ChatException的定义: package SimpleChat; public class ChatException extends Exception{ /**

简易聊天程序教程(五)客户端的登陆和注册窗口

源代码下载链接:http://download.csdn.net/detail/sky453589103/9514686 如果有什么问题,欢迎留言. 其实大家也能想到,登陆和注册窗口其实很相似的,而注册窗口总是比登陆窗口多一些内容. 先来说说登陆窗口.登陆窗口的界面如下图: 登陆窗口继承字Dialog类,而不是继承自JFrame类.登陆窗口显示在屏幕中间,通过下面的方法就可以达到效果: setLocationRelativeTo(null); 在构造函数中调用这个方法,就能显示在屏幕中央,如果参

简易聊天程序教程(三)服务器的多线程

源代码下载链接:http://download.csdn.net/detail/sky453589103/9514686 如果有什么问题,欢迎留言. 如果一个服务器只能为两个用户提供服务器,那就真的是太渣了.很多时候,聊天的客户都会大于两个.因此需要提高并发量. 在Java中使用多线程还是很方便的.我在这个服务器程序使用的是实现Runnable接口的方法来定义自己的多线程操作.通过重写run方法,来实现自己的多线程操作. 每个线程都会有一个client成员变量,这个成员变量用来记录客户端的Soc

简易聊天程序教程(二)服务器的基本功能

源代码下载链接:http://download.csdn.net/detail/sky453589103/9514686 如果有什么问题,欢迎留言. 我设计的时候是先从服务器端开始设计的,服务器端先给出接口,然后客户端针对接口编程. 在说服务器的代码之前先说说数据库的设计吧. 数据的设计是简单的,只有两个表: create database SimpleChat; CREATE TABLE IF NOT EXISTS Account ( username varchar(50) NOT NULL

第27课 应用程序中的主窗口

1. 主窗口的概念 (1)主窗口是与用户进行长时间交互的顶层窗口 (2)程序的绝大多数功能直接由主窗口提供 (3)主窗口通常是应用程序启动后显示的第一个窗口 (4)整个程序由一个主窗口和多个对话框组成 2. Qt中的主窗口 (1)Qt开发平台中直接支持主窗口的概念 (2)QMainWindow是Qt中主窗口的基类 (3)QMainWindow继承于QWidget是一种容器类型的组件 3. QMainWindow中封装的秘密 (1)菜单栏(2)工具栏(3)中心组件(4)停靠组件(5)状态栏 4.

基于C# Winform的简易聊天程序[第一篇-两端通信]

程序简介 本聊天程序支持局域网内部客户端与服务端之间的互相通信. 原理 启动服务端后,服务端通过持续监听客户端发来的请求,一旦监听到客户端传来的信息后,两端便可以互发信息了.服务端需要绑定一个IP,用于客户端在网络中寻找并建立连接.信息发送原理:将手动输入字符串信息转换成机器可以识别的字节数组,然后调用套接字的Send()方法将字节数组发送出去.信息接收原理:调用套接字的Receive()方法,获取对端传来的字节数组,然后将其转换成人可以读懂的字符串信息. 界面设计 - 服务端 IP文本框 na

PHP制作简易聊天程序

近几天来,突然在查阅PHP中文手册时,看到了用PHP制作聊天室的示例,于是一时心血来潮也用PHP写了一个简易的WEB聊天室应用,在写聊天室的过程中,我遇到的问题其实不算很多,因为用php制作聊天室的原理是非常简单的,也许这与我自身思考问题的方式有关,我往往喜欢把任何看似复杂的东西简单化,我相信表面复杂的事物,其实都蕴含着简易原理,我的这种思维模式在这次WEB聊天应用的制作中起到了作用,下面我就将PHP制作WEB聊天室的原理给大家做一个介绍: 首先我们要建立一个WEB框架,这个框架也就是利用HTM

.Net学习笔记----2015-07-06(简易聊天程序)

直接上代码,注释俺写了不少,留着参考 服务端: 1 namespace sever 2 { 3 public partial class Form1 : Form 4 { 5 public Form1() 6 { 7 InitializeComponent(); 8 } 9 10 private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) 11 { 12 13 } 14 15 16 private void bt