⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chatframe.java

📁 一个简易的java画图软件
💻 JAVA
字号:
package app.pane;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import draw.View;

import skin.Display;

import net.NetMessage;

import app.Application;

/**
 * 聊天面板,可以附在响应画布上面
 * 
 * @author Thihy
 * 
 */
public class ChatFrame extends JInternalFrame {
	View view;
	JPanel chatPane;
	JTextArea chatField;
	JPanel contentPane;
	JTextPane chatContent;
	JButton hideShowButton;
	String chatText = "";
	String userName = null;// 本机聊天者的名称,初始为null
	Display display = new Display();
	int chatPaneWidth = 300;
	HashMap<String, String> codeStr;

	boolean isHidden;
	boolean canHide;
	ImageIcon hideIcon = new ImageIcon(getClass()
			.getResource("images/hide.gif")), showIcon = new ImageIcon(
			getClass().getResource("images/show.gif"));

	/**
	 * 初始化聊天面板
	 * 
	 * @param view
	 *            聊天面板所在的画布
	 * @param canHide
	 *            能否隐藏
	 */
	public ChatFrame(View view, boolean canHide) {
		super("ChatDemo");
		this.view = view;
		this.isHidden = false;
		this.canHide = canHide;

		chatPane = new JPanel();
		chatPane.setBorder(new EdgedBorder(Color.LIGHT_GRAY));

		chatPane.setLayout(new BorderLayout());
		contentPane = creatContentPane();
		contentPane.setVisible(!isHidden);
		contentPane.setPreferredSize(new Dimension(chatPaneWidth, 50));

		chatPane.add(contentPane, BorderLayout.CENTER);
		chatPane.add(creatHideShowBar(), BorderLayout.WEST);
		initCodeStr();
	}

	/**
	 * 初始化codeStr
	 */
	public void initCodeStr() {
		codeStr = new HashMap<String, String>();

		codeStr.put("惊讶", "0.gif");
		codeStr.put("苦闷", "1.gif");
		codeStr.put("痴情", "2.gif");
		codeStr.put("发呆", "3.gif");
		codeStr.put("帅气", "4.gif");
		codeStr.put("想哭", "5.gif");
		codeStr.put("美眉", "6.gif");
		codeStr.put("呵呵", "7.gif");
		codeStr.put("睡觉", "8.gif");
		codeStr.put("大哭", "9.gif");
		codeStr.put("发窘", "10.gif");
		codeStr.put("发怒", "11.gif");
		codeStr.put("闲适", "12.gif");
		codeStr.put("嗤笑", "13.gif");
		codeStr.put("微笑", "14.gif");
		codeStr.put("smile", "14.gif");
	}

	/**
	 * 获取聊天面板
	 * 
	 * @return 聊天面板
	 */
	public JPanel getChatPane() {
		return chatPane;
	}

	/**
	 * 创建聊天面板的主面板<br/> 主要有 显示消息面板 输入消息面板
	 * 
	 * @return 聊天面板的主面板
	 */
	private JPanel creatContentPane() {
		final JPanel contentPane = new JPanel();
		contentPane.setLayout(new BorderLayout());

		// 聊天窗口标题
		JPanel chatTitlePane = new JPanel();
		chatTitlePane.setLayout(new FlowLayout(FlowLayout.LEFT));
		JLabel chatTitle = new JLabel("聊天窗口");
		chatTitlePane.add(chatTitle);

		contentPane.add(chatTitlePane, BorderLayout.NORTH);

		// 聊天显示消息栏
		chatContent = new JTextPane();
		chatContent.setEditable(false);

		JScrollPane chatChontentScroller = new JScrollPane();
		chatChontentScroller.setViewportView(chatContent);
		chatChontentScroller
				.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		contentPane.add(chatChontentScroller, BorderLayout.CENTER);

		// 聊天输入栏
		chatField = new JTextArea(5, 30);

		chatField.setLayout(null);
		chatField.setLineWrap(true);
		chatField.setFont(new Font("宋体", Font.PLAIN, 16));
		JScrollPane chatFieldScroller = new JScrollPane();
		chatFieldScroller.setViewportView(chatField);
		chatFieldScroller
				.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		chatFieldScroller
				.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		contentPane.add(chatFieldScroller, BorderLayout.SOUTH);

		ChatAction chatAction = new ChatAction();

		// 当点击enter则发送消息,ctrl+enter则回车
		chatField.registerKeyboardAction(chatAction, "Send", KeyStroke
				.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED);
		chatField.registerKeyboardAction(chatAction, "Enter", KeyStroke
				.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK),
				JComponent.WHEN_FOCUSED);

		return contentPane;
	}

	/**
	 * 切换隐藏 在显示和隐藏中切换,除非指定不能隐藏
	 */
	public void switchHideShow() {
		if (isHidden) {// 当前是隐藏状态,现在切换至正常状态
			contentPane.setVisible(true);
			contentPane.setPreferredSize(new Dimension(chatPaneWidth, 50));
			hideShowButton.setIcon(hideIcon);
			isHidden = false;
		} else if (canHide) {// 当前是正常状态,现在切换至隐藏状态
			contentPane.setPreferredSize(new Dimension(chatPaneWidth, 50));
			contentPane.setVisible(false);
			hideShowButton.setIcon(showIcon);
			isHidden = true;
		}
	}

	/**
	 * 分割条上有一个按钮:在隐藏和显示中切换。使得主窗口的空间可以大一点。
	 * 
	 * @return 分割条
	 */
	public JToolBar creatHideShowBar() {
		JToolBar hideShowBar = new JToolBar();
		hideShowBar.setOrientation(SwingConstants.VERTICAL);
		hideShowBar.setFloatable(false);
		hideShowBar.setMargin(new Insets(0, 0, 0, 0));

		hideShowButton = new JButton();
		hideShowButton.setMargin(new Insets(0, 0, 0, 0));
		hideShowButton.setPreferredSize(new Dimension(16, 16));

		hideShowButton.addActionListener(new AbstractAction() {
			@Override
			public void actionPerformed(ActionEvent e) {
				switchHideShow();
			}
		});

		if (isHidden)
			hideShowButton.setIcon(showIcon);
		else
			hideShowButton.setIcon(hideIcon);

		hideShowBar.add(hideShowButton);

		return hideShowBar;
	}

	/**
	 * 从外界接收消息<br/> 消息有消息头,这个类只接受MES_CHAT和MES_SERVER_NOTICE
	 * 
	 * @param netMes
	 *            接受到的消息
	 */
	public void receiveMessage(NetMessage netMes) {
		if (netMes == null || netMes.messageContent == null) {
			if (Application.DEBUG > 6) {
				System.out.println("哪里来的空消息:View.receiveMessage()");
			}
			return;
		}

		// 判断消息头
		if (netMes.messageHeader.equals(NetMessage.MES_CHAT)) {// 如果是聊天内容
			// 消息内容开始是用户名称
			String text = (String) netMes.messageContent;
			int index = text.indexOf(':');
			if (index >= 0 && index < text.length() - 1) {
				String senderUsername = text.substring(0, index);
				String content = text.substring(index + 1, text.length());
				showMenssage(content, senderUsername);// 显示消息
			} else {
				if (Application.DEBUG > 6)
					System.out.println("聊天窗口接收到一个没有用户名称的消息");
			}
		} else if (netMes.messageHeader.equals(NetMessage.MES_SERVER_NOTICE)) {// 如果是服务器的通知
			showServerNotice((String) netMes.messageContent);
		} else {
			if (Application.DEBUG > 6) {
				System.out.println("聊天窗口接收到一个未知消息类型的消息");
			}
		}
	}

	/**
	 * 向外界发送消息,这个不具有消息头 会响应setname指令
	 * 
	 * @param text
	 *            发送的消息的内容
	 */
	private void sendMessage(String text) {
		if (text.toLowerCase().startsWith("/setname:")) {// 设置名称指令
			int index = text.indexOf(':');
			++index;
			sendNewName(text.substring(index));
			return;
		} else {// 否则向外界发送消息
			// 在这个窗口中显示内容
			showMenssage(text);

			// 向外界发送消息
			sendMessage(NetMessage.MES_CHAT, text);
		}
	}

	/**
	 * 核实新的名称是否有效<br/>
	 * 
	 * @param newName
	 *            新的名称
	 * @return 当不含冒号且长度不小于1时返回真
	 */
	private boolean checkNewName(String newName) {
		if (newName.length() < 1)
			return false;

		int index = newName.indexOf(':');
		return index == -1;
	}

	/**
	 * 向外界发送新的名称 服务器会接受这个消息,并且更新名称映射表
	 * 
	 * @param newName
	 */
	private void sendNewName(String newName) {
		// check name:无冒号
		System.out.println("newname:" + newName);
		newName = newName.trim();
		if (!checkNewName(newName))
			return;
		sendMessage(NetMessage.MES_SET_USER_NAME, newName);
		showString("你已经将名称更改为" + newName + ",请等待服务器响应\r\n",
				new Color(0xffcc00), true, true, 13);
	}

	/**
	 * 向外界发送消息
	 * 
	 * @param mesHeader
	 *            发送的消息头
	 * @param mesContent
	 *            发送的消息内容
	 */
	private void sendMessage(String mesHeader, String mesContent) {
		view.sendMessage(new NetMessage(mesHeader, mesContent));
	}

	/**
	 * 显示内容
	 * 
	 * @param str
	 *            显示的字符串
	 * @param color
	 *            显示的颜色
	 * @param bold
	 *            是否为粗体
	 * @param italic
	 *            是否为斜体
	 * @param fontSize
	 *            字体的大小
	 */
	public void showString(String str, Color color, boolean bold,
			boolean italic, int fontSize) {
		SimpleAttributeSet attrSet = new SimpleAttributeSet();

		StyleConstants.setForeground(attrSet, color);
		StyleConstants.setBold(attrSet, bold);
		StyleConstants.setItalic(attrSet, italic);
		if (fontSize > 3) {
			StyleConstants.setFontSize(attrSet, fontSize);
		}
		Document doc = chatContent.getDocument();
		try {
			doc.insertString(doc.getLength(), str, attrSet);
		} catch (BadLocationException e) {
			if (Application.DEBUG > 0)
				System.out.println("插入字符失败: " + e);
		}

		// 将插入符置于末尾,这样才能够自动滚动
		chatContent.setCaretPosition(chatContent.getDocument().getLength());
	}

	/**
	 * 显示内容的快捷方式 颜色是深灰色,常规字体样式,大小为14
	 * 
	 * @param text
	 *            显示内容
	 */
	public void showString(String text) {
		showString(text, Color.darkGray, false, false, 14);
	}

	// 上一次的消息所有者名称,如果相同则不再显示名称
	private String lastMessageSenderName = null;

	/**
	 * 本地显示消息的快捷方式 名称为“我”
	 * 
	 * @param text
	 *            待显示的内容
	 */
	private void showMenssage(String text) {
		showMenssage(text, "我");
	}

	/**
	 * 显示消息,会根据指定的用户名进行显示
	 * 
	 * 
	 * @param text
	 *            待显示的内容
	 * @param SenderName
	 *            发送者的名称
	 */
	public void showMenssage(String text, String SenderName) {
		if (SenderName != null && !SenderName.equals(lastMessageSenderName)) {
			lastMessageSenderName = SenderName;
			showString(SenderName + "说    ", new Color(0x336600), true, false,
					16);
			showString("于 ", new Color(0x9999ff), false, false, 10);
			showString(new SimpleDateFormat("MM月dd日 HH:mm:ss")
					.format(new Date())
					+ "\r\n", new Color(0x9999ff), false, true, 10);
		}
		// 显示解码后的文本,会有表情等
		showUncodeText(text);
	}

	/**
	 * 显示服务器的消息
	 * 
	 * @param text
	 *            待显示的内容
	 */
	public void showServerNotice(String text) {
		showString("服务器通知:" + text + "\r\n", new Color(0xffcc00), true, true,
				13);
		lastMessageSenderName = null;
	}

	/**
	 * 显示经过转义之后的文本 表情的代表字符必须以‘/’开始, 要取消转义,在其之前加上'/’即可
	 * 
	 * @param text
	 */
	private void showUncodeText(String text) {
		int size = text.length();
		int i = 0;
		int lastIndex = 0;
		while (i < size - 1) {
			++i;
			if (text.charAt(i - 1) == '/') { // 可能需要转义
				if (text.charAt(i) != '/') { // 两个‘/’表示取消后面的转义
					String uncodeStr;
					if ((uncodeStr = getUncodeIndex(text.substring(i))) != null) {
						showString(text.substring(lastIndex, i - 1));
						showString(" ");// 这样连续两个icon不会重叠在一起
						chatContent
								.insertIcon(new ImageIcon(
										getClass()
												.getResource(
														"faces/"
																+ codeStr
																		.get(uncodeStr))));
						showString(" ");
						i += uncodeStr.length();
						lastIndex = i;
					}
				} else {
					showString(text.substring(lastIndex, i));
					++i;
					lastIndex = i;
				}
			}
		}
		if (lastIndex < size) {
			showString(text.substring(lastIndex, size));
		}
		showString("\r\n");
	}

	/**
	 * 判断指定的字符串是否以一个转义字符开始 如果是,则返回转义字符的唯一索引值
	 * 
	 * @param substring
	 *            指定的字符串
	 * @return 转义字符的唯一索引值,如果不是以转义字符开始,返回-1
	 */
	private String getUncodeIndex(String substring) {
		Iterator<String> iter = codeStr.keySet().iterator();
		while (iter.hasNext()) {
			String str = iter.next();
			if (substring.startsWith(str))
				return str;
		}
		return null;
	}

	/**
	 * 内部类,输入Action 对Enter和Ctrl+Enter的处理就在这里
	 * 
	 * @author Thihy
	 * 
	 */
	public class ChatAction extends AbstractAction {

		@Override
		public void actionPerformed(ActionEvent e) {

			if (e.getActionCommand().equals("Send")) { // 发送文本,没有回车符
				String text = chatField.getText();
				if (text.equals(""))
					return;
				sendMessage(text);
				chatField.setText("");
			} else if (e.getActionCommand().equals("Enter")) {
				chatField.append("\r\n");
			} else if (e.getActionCommand().equals("Close")) {
				dispose();
			}
		}

	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -