java swing 聊天表情功能的實現(帶完整代碼)

 

前言:

 用java swing做聊天程序,可能是沒事找事,也可能是大才小用

不過作爲畢業設計還是綽綽有餘了,既然選擇了就做吧

其中比較重要的功能可能就是是聊天表情了,當然字體也重要

經過多天來的資料查找和實踐,終於做出來了,方法不是很先進,但是運行效果良好

 

下面是總結出的一個示例

主要功能:

1.聊天表情框的顯示,

2.聊天信息(文本信息、字體信息、表情信息、用戶)的傳輸udp,

3.聊天信息的顯示(表情和文本混合顯示),

4.震動,

5.懸浮提示框

難點1:表情框

難點2:表情(信息)的顯示和傳輸

難點3:表情和文本的混合

難點4:字體屬性的設置和傳輸

 

解決方案

 一、表情框

         使用javax.swing.JWindow類(無修飾的窗體類),繼承這個類可以實現,在一個什麼都沒有的空窗體(沒有標題欄,沒有最大、最小化,沒有關閉按鈕等),我們可以設置其佈局爲網格佈局setLayout(ew   GridLayout(7,15) ),然後在每個格子裏再加上圖片(圖片當然要先放在JLabel或JPanel裏比較好,設置邊框,添加鼠標監聽)等

代碼如下:

 表情圖片所在目錄:com.zou.chat.qqdefaultface 下放105張表情圖  名字爲0.gif,1.gif——104.gif

注意目錄結構:com.zou.chat.qqdefaultface 下面放圖,com.zou.chat下放java文件,紅色標註部分保證一致

PicsJWindow.java:

package com.zou.chat;
import   java.awt.*; 

import   javax.swing.*; 

import   java.awt.event.*; 
/** 
  *   <p> Title:   pictures</p> 
  * 
  *   <p> Description:   </p> 
  * 
  *   <p> Copyright:   Copyright   (c)   2011 </p> 
  * 
  *   <p> Company:   </p> 
  * 
  *   @author   not   attributable 
  *   @version   1.0 
  */ 
public   class   PicsJWindow  extends   JWindow   { 
	private static final long serialVersionUID = 1L;
	GridLayout   gridLayout1   =   new   GridLayout(7,15); 
    JLabel[]   ico=new   JLabel[105]; /*放表情*/
    int  i;
    ChatFrame   owner;
    String[] intro = {"","","","","","","","","","","","","","","",
    		"","","","","","","","","","","","","","","",
    		"","","","","","","","","","","","","","","",
    		"","","","","","","","","","","","","","","",
    		"","","","","","","","","","","","","","","",
    		"","","","","","","","","","","","","","","",
    		"","","","","","","","","","","","","","","",};/*圖片描述*/
    public   PicsJWindow(ChatFrame   owner)   { 
        super(owner); 
        this.owner=owner; 
        try   { 
            init(); 
            this.setAlwaysOnTop(true); 
        } 
        catch   (Exception   exception)   { 
            exception.printStackTrace(); 
        } 
    } 
    private   void   init()   throws   Exception   { 
		this.setPreferredSize(new Dimension(28*15,28*7));
		JPanel p = new JPanel();
		p.setOpaque(true);
		this.setContentPane(p);
    	p.setLayout(gridLayout1);
        p.setBackground(SystemColor.text);		
		String fileName = "";
        for(i=0;i <ico.length;i++){ 
            fileName= "qqdefaultface/"+i+".gif";/*修改圖片路徑*/ 
            ico[i] =new   JLabel(new  ChatPic(PicsJWindow.class.getResource(fileName),i),SwingConstants.CENTER);
            ico[i].setBorder(BorderFactory.createLineBorder(new Color(225,225,225), 1));
            ico[i].setToolTipText(i+"");
            ico[i].addMouseListener(new   MouseAdapter(){ 
                public   void   mouseClicked(MouseEvent  e){ 
                	if(e.getButton()==1){
                		JLabel cubl = (JLabel)(e.getSource());
                		ChatPic cupic = (ChatPic)(cubl.getIcon());
                		owner.insertSendPic(cupic);
                		cubl.setBorder(BorderFactory.createLineBorder(new Color(225,225,225), 1));
                    	getObj().dispose();
                	}
                }
				@Override
				public void mouseEntered(MouseEvent e) {
		            ((JLabel)e.getSource()).setBorder(BorderFactory.createLineBorder(Color.BLUE));
				}
				@Override
				public void mouseExited(MouseEvent e) {
					((JLabel)e.getSource()).setBorder(BorderFactory.createLineBorder(new Color(225,225,225), 1));
				} 
                
            }); 
            p.add(ico[i]); 
        } 
        p.addMouseListener(new MouseAdapter(){
			@Override
			public void mouseExited(MouseEvent e) {
            	getObj().dispose(); 
			}
        	
        });
    } 
	@Override
	public void setVisible(boolean show) {
		if (show) {
			determineAndSetLocation();
		}
		super.setVisible(show);
	}	
	private void determineAndSetLocation() {
		Point loc = owner.getPicBtn().getLocationOnScreen();/*控件相對於屏幕的位置*/
		setBounds(loc.x-getPreferredSize().width/3, loc.y-getPreferredSize().height,
				getPreferredSize().width, getPreferredSize().height);
	}
    private   JWindow   getObj(){ 
        return   this; 
    } 

}
ChatPic.java

/*自定義的ImageIcon的子類,在聊天窗體添加表情時,方便取出圖片的描述信息*/

package com.zou.chat; import java.net.URL;

import javax.swing.ImageIcon; public class ChatPic extends ImageIcon{  /**   *圖片描述   */  private static final long serialVersionUID = 1L;  int im;//圖片代號    public int getIm() {   return im;  }  public void setIm(int im) {   this.im = im;  }  public ChatPic(URL url,int im){   super(url);   this.im = im;  } }

    

 二、三、四 :表情(信息)的顯示和傳輸,表情和文本的混合 字體屬性的設置和傳輸 

顯示錶情通過 JTextPane的StyledDocument對象的添加圖片功能實現,傳輸時不直接傳圖片,只傳相對於文本的位置和代號,通過document取出表情的位置和代號,自定義封裝規則(這樣對方程序收到後就可以在按規則還原位置和代號,在指定位置顯示圖片),這樣表情和文本就可以混合了,字體一樣定義傳輸規則,比如消息串可以這樣定義的 userinfo*font*message

用String.spilt()分離

userinfo代表 用戶信息字符串表示,爲了簡單就代表用戶名,當然其中不能包括*號,不然 把userinfo*font*message 根據*分離出來就不能取得正確的userinfo,

 font字體信息 font的可爲內容爲 fontname|fontsize|fontColor    ”宋體| 10|1-1-1",可以繼續取出fontname      fontsize  fontColor ,用其設置要插入的文字的格式

 

JTextPane的使用:

JTextPane  tp = new JTextPane();

StyledDocument doc = jp.getStyledDocument();//這個對象可以完成下列操作,很方便,實現圖文混和顯示

既可以插入文本和文本樣式,

SimpleAttributeSet attrSet;//參數需要

  doc .insertString(doc .getLength(), "Hello,SytedDocument!\n",attrib.getAttrSet());

      public SimpleAttributeSet getAttrSet() {
               attrSet = new SimpleAttributeSet();
               StyleConstants.setFontFamily(attrSet, "宋體");
               StyleConstants.setBold(attrSet, false);
               StyleConstants.setItalic(attrSet, false);
              StyleConstants.setFontSize(attrSet, size);
              StyleConstants.setForeground(attrSet, Color.RED);
       return attrSet;
  }

也可以插入圖片,

String fileName= "qqdefaultface/1.gif";

doc .insertIcon(new  ImageIcon(PicsJWindow.class.getResource(fileName)));

還可以設置每次插入的文字位置,

      int pos = 0;  // 位置0到 長度減1,不要越界

     doc .setCaretPosition(pos); /*設置插入位置*/

     doc .insertString(doc .getLength(), "Hello,SytedDocument!\n",attrib.getAttrSet());

圖片位置,

     doc .setCaretPosition(pos);/*設置插入位置*/

doc .insertIcon(new  ImageIcon(PicsJWindow.class.getResource(fileName)));

也可以取出每次插入的文本和圖片信息

String text = tp.getText();//取文本

//取圖

 private List<PicInfo> myPicInfo = new LinkedList<PicInfo>();

 private String buildPicInfo(){
  StringBuilder sb = new StringBuilder("");
  //遍歷jtextpane找出所有的圖片信息封裝成指定格式
    for(int i = 0; i < this.jpMsg.getText().length(); i++){
              if(docMsg.getCharacterElement(i).getName().equals("icon")){
               //doc = (ChatPic)
               Icon icon = StyleConstants.getIcon(doc.getStyledDocument().getCharacterElement(i).getAttributes());
               ChatPic cupic = (ChatPic)icon;
               PicInfo picInfo= new PicInfo(i,cupic.getIm()+"");
               myPicInfo.add(picInfo);
               sb.append(i+"&"+cupic.getIm()+"+");
             }
          }
    System.out.println(sb.toString());
    return sb.toString();
    //return null;
 }

後續代碼:ChatFrame.java

package com.zou.chat;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.FontUIResource;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
/**
 * 聊天窗體類
 * @author yangxing zou
 * @version 0.1
 */
public class ChatFrame extends JFrame implements MouseListener{
	private static final long serialVersionUID = 1L;
	public final int fwidth = 550;
	public final int fheight = 500;
	/* 左邊和右邊要顯示的界面 */
	public JLabel left = new JLabel();
	JScrollPane jspChat;
	/*聊天內容*/
	private JTextPane jpChat;
	/*要發送的內容*/
	private JTextPane jpMsg;
	JScrollPane jspMsg;
	/* 插入文字樣式用*/
	private StyledDocument docChat = null;
	private StyledDocument docMsg = null; 

	private JButton btnSend;
	/*好友的ip*/
	/*private String friendIP;*/
	/*好友接收消息的端口*/
	/*private int friendPort;*/
	/*字體名稱;字號大小;文字顏色*/
	private JComboBox fontName = null, fontSize = null,fontColor = null; 
	/*插入按鈕;清除按鈕;插入圖片按鈕*/
	private JButton b_shake=null,b_pic, b_remove = null;
	private static final Color TIP_COLOR = new Color(255, 255, 225);
	 /* 錯誤信息氣泡提示*/
	private CoolToolTip error_tip;
	/*表情框*/
	private PicsJWindow picWindow;
	private List<PicInfo> myPicInfo = new LinkedList<PicInfo>();
	private List<PicInfo> receivdPicInfo = new LinkedList<PicInfo>();
	class PicInfo{
		/* 圖片信息*/
		int pos;
		String val;
		public PicInfo(int pos,String val){
			this.pos = pos;
			this.val = val;
		}
		public int getPos() {
			return pos;
		}
		public void setPos(int pos) {
			this.pos = pos;
		}
		public String getVal() {
			return val;
		}
		public void setVal(String val) {
			this.val = val;
		}
		
	}
	public JButton getPicBtn(){
		return b_pic;
	}
	public ChatFrame() {
		init();
	}
	/**
	 * 插入圖片
	 * 
	 * @param icon
	 */
	public void insertSendPic(ImageIcon imgIc) {
		//jpMsg.setCaretPosition(docChat.getLength()); // 設置插入位置
		jpMsg.insertIcon(imgIc); // 插入圖片
		System.out.print(imgIc.toString());
		//insert(new FontAttrib()); // 這樣做可以換行
	}
	/*
	 * 重組收到的表情信息串
	 */
	public void receivedPicInfo(String picInfos){
		String[] infos = picInfos.split("[+]");
		for(int i = 0 ; i < infos.length ; i++){
			String[] tem = infos[i].split("[&]");
			if(tem.length==2){
				PicInfo pic = new PicInfo(Integer.parseInt(tem[0]),tem[1]);
				receivdPicInfo.add(pic);
			}
		}
	}
	/**
	 * 重組發送的表情信息
	 * @return 重組後的信息串  格式爲   位置|代號+位置|代號+……
	 */
	private String buildPicInfo(){
		StringBuilder sb = new StringBuilder("");
		//遍歷jtextpane找出所有的圖片信息封裝成指定格式
		  for(int i = 0; i < this.jpMsg.getText().length(); i++){ 
              if(docMsg.getCharacterElement(i).getName().equals("icon")){
            	  //ChatPic = (ChatPic)
            	  Icon icon = StyleConstants.getIcon(jpMsg.getStyledDocument().getCharacterElement(i).getAttributes());
            	  ChatPic cupic = (ChatPic)icon;
            	  PicInfo picInfo= new PicInfo(i,cupic.getIm()+"");
            	  myPicInfo.add(picInfo);
            	  sb.append(i+"&"+cupic.getIm()+"+");
             } 
          }
		  System.out.println(sb.toString());
		  return sb.toString();
		  //return null;
	}
	
	/**
	 * 初始化窗體
	 */
	private void init() {
		setLayout(new BorderLayout());
		/*this.setUndecorated(true);*/
/*		getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
*/		setSize(fwidth, fheight);
		this.setMinimumSize(new Dimension(fwidth, fheight));
		this.getContentPane().setBackground(Color.GRAY);
		setResizable(false);
		setLocationRelativeTo(null);
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(1);
			}
		});
		this.addComponentListener(new ComponentAdapter(){

			@Override
			public void componentResized(ComponentEvent e) {
				ChatFrame.this.picWindow.dispose();
			}

			@Override
			public void componentMoved(ComponentEvent e) {
				ChatFrame.this.picWindow.dispose();
			}

			@Override
			public void componentHidden(ComponentEvent e) {
				ChatFrame.this.picWindow.dispose();
			}
			
		});
		/*窗體前置*/
		setAlwaysOnTop(true); 
		/*聊天信息框*/
		jpChat = new JTextPane();
		jpChat.addMouseListener(this);
		jpChat.setEditable(false);
		jspChat = new JScrollPane(jpChat,
				ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		/*用戶聊天信息輸入框*/
		jpMsg = new JTextPane();
		jpMsg.addMouseListener(this);
		jspMsg = new JScrollPane(jpMsg,
				ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

		jspMsg.setPreferredSize(new Dimension(100, 100));
		error_tip = new CoolToolTip(this, jspMsg, TIP_COLOR, 3, 10);

		/*發送按鈕*/
		btnSend = new JButton("發送");
		btnSend.setFocusable(false);
		/*獲得JTextPane的Document用於設置字體*/
		docChat = jpChat.getStyledDocument();
		docMsg = jpMsg.getStyledDocument();

		/*添加鼠標事件監聽*/
		btnSend.addMouseListener(this);
		/*字體區*/
		JLabel lblSend = new JLabel();
		lblSend.setLayout(new FlowLayout(FlowLayout.RIGHT));
		String[] str_name = { "宋體", "黑體", "Dialog", "Gulim" };
		String[] str_Size = { "12", "14", "18", "22", "30", "40" };
		//String[] str_Style = { "常規", "斜體", "粗體", "粗斜體" };
		String[] str_Color = { "黑色", "紅色", "藍色", "黃色", "綠色" };
		fontName = new JComboBox(str_name);
		fontSize = new JComboBox(str_Size);
		fontColor = new JComboBox(str_Color);
		Box box = Box.createHorizontalBox();
		box.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
		box.add(new JLabel("字體:"));
		box.add(fontName);

		box.add(Box.createHorizontalStrut(3));
		box.add(new JLabel("字號:"));
		box.add(fontSize);
		box.add(Box.createHorizontalStrut(3));
		box.add(new JLabel("顏色:"));
		box.add(fontColor);
		box.add(Box.createHorizontalStrut(3));
		box.add(btnSend);

		JPanel PaneLeftSouth = new JPanel();
		PaneLeftSouth.setLayout(new BorderLayout());

		b_pic = new JButton("表情");
		b_pic.setFocusable(false);
		b_shake = new JButton("震動");
		b_shake.setFocusable(false);
		b_remove = new JButton("清空");
		b_remove.setFocusable(false);
		picWindow = new PicsJWindow(this);
		b_pic.addMouseListener(this);
		b_remove.addMouseListener(this);
		b_shake.addMouseListener(this);
		Box box_1 = Box.createHorizontalBox();
		box_1.add(b_pic);
		box_1.add(b_shake);
		box_1.add(b_remove);
		
		PaneLeftSouth.add(box_1, BorderLayout.NORTH);//字體、表情、震動
		PaneLeftSouth.add(jspMsg, BorderLayout.CENTER);
		PaneLeftSouth.add(box, BorderLayout.SOUTH);
		left.setLayout(new BorderLayout());
		left.setOpaque(false);
		PaneLeftSouth.setBackground(Color.CYAN);
		left.add(jspChat, BorderLayout.CENTER);
		left.add(PaneLeftSouth, BorderLayout.SOUTH);
		add(left, BorderLayout.CENTER);
		
		new receivMsgThread().start();
	}
	@Override
	public void mouseClicked(MouseEvent arg0) {}
	@Override
	public void mouseEntered(MouseEvent arg0) {
		error_tip.setVisible(false);
	}
	@Override
	public void mouseExited(MouseEvent arg0) {}
	@Override
	public void mousePressed(MouseEvent e) {
		picWindow.setVisible(false);
	}
	@Override
	public void mouseReleased(MouseEvent e) {
		if (getY() <= 0) {
			setLocation(getX(), 0);
		}
		if (e.getButton() != 1)
			return;/*不是左鍵*/

		JComponent source = (JComponent) e.getSource();
		/*鼠標釋放時在事件源內,才響應單擊事件*/
		if (e.getX() >= 0 && e.getX() <= source.getWidth() && e.getY() >= 0
				&& e.getY() <= source.getHeight()) {
			if (source == btnSend){
					sendMsg();
			}else if (source == this.b_shake){
					sendShake();
			} else if (source == this.b_pic){
				picWindow.setVisible(true);
			} else if (source == this.b_remove){
				jpChat.setText("");
				jpChat.revalidate();
			}
		}
	}
	/**
	 * 向好友發送震動
	 */
	public void sendShake(){
		String uname = Sender.localIP+":"+Sender.SendPort;
		if (!Sender.sendUDPMsg(MsgType.SHAKE, uname, Sender.localIP, Sender.SendPort,"shake")){
			error_tip.setText("發送失敗!");
			error_tip.setVisible(true);
		}
		insert("你向 "+ uname +" 發送了一個震動!");
	}
	/**
	 * 震動三秒以上
	 * @param uname
	 */
	public void shake(String uname){
		setExtendedState(Frame.NORMAL);
		setVisible(true);
		insert(uname+" 給你發了一個震動!");
		new Thread(){
			long begin = System.currentTimeMillis();
			long end = System.currentTimeMillis();
			Point p = ChatFrame.this.getLocationOnScreen();
			public void run(){
				int i = 1;
				while((end-begin)/1000<3){
					ChatFrame.this.setLocation(new Point((int)p.getX()-5*i,(int)p.getY()+5*i));
					end = System.currentTimeMillis();
					try {
						Thread.sleep(5);
						i=-i;
						ChatFrame.this.setLocation(p);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
	}
	/**
	 * 發送消息
	 */
	private FontAndText myFont = null;
	public void sendMsg() {
		String message = jpMsg.getText();
		if (message.length() == 0) {
			error_tip.setText("請輸入聊天信息!");
			error_tip.setVisible(true);
			return;
		}
		if(message.length()>100){
			error_tip.setText("消息最多一百個字符!你要發送的爲"+message.length() + "個字符!");
			error_tip.setVisible(true);
			return;
		}
		
		String uname = Sender.localIP+":"+Sender.chatPort;
		myFont = getFontAttrib();
		if (Sender.sendUDPMsg(MsgType.CHAT, uname, Sender.localIP, Sender.SendPort,
				myFont.toString())) {
			addMeg(uname);
			this.jpMsg.setText("");
		} else {
			error_tip.setText("發送消息失敗!");
			error_tip.setVisible(true);
		}
	}
	/**
	 * 追加新消息到聊天窗體
	 */
	SimpleDateFormat sf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
	FontAndText dateFont = new FontAndText("","宋體",20,Color.BLUE);
	public void addMeg(String uname) {
		String msg =  uname + " " + sf.format(new Date());
		dateFont.setText(msg);
		insert(dateFont);
		pos2 = jpChat.getCaretPosition();
		myFont.setText(jpMsg.getText());
		insert(myFont);
		insertPics(false);
	}
	public void addRecMsg(String uname,String message){
		setExtendedState(Frame.NORMAL);
		//setVisible(true);
		String msg =  uname + " " + sf.format(new Date());
		dateFont.setText(msg);
		insert(dateFont);/*時間和用戶信息*/
		int index = message.lastIndexOf("*");
		
		System.out.println("index="+index);
		/*很重要的,記錄下聊天區域要插入聊天消息的開始位置,*/
		pos1 = jpChat.getCaretPosition();
		if(index>0 && index < message.length()-1){/*存在表情信息*/
			FontAndText attr = getRecivedFont(message.substring(0,index));
			insert(attr);
			receivedPicInfo(message.substring(index+1,message.length()));
			insertPics(true);
		}else{
			FontAndText attr = getRecivedFont(message);
			insert(attr);
		}
	}
	/**
	 * 將收到的消息轉化爲自定義的字體類對象
	 * @param message 收到的聊天信息
	 * @return  字體類對象
	 */
	public FontAndText getRecivedFont(String message){
		String[] msgs = message.split("[|]");
		String fontName = "";
		int fontSize = 0;
		String[] color;
		String text = message;
		Color fontC = new Color(222,222,222);
		if(msgs.length>=4){/*這裏簡單處理,表示存在字體信息*/
			fontName = msgs[0];
			fontSize = Integer.parseInt(msgs[1]);
			color = msgs[2].split("[-]");
			if(color.length==3){
				int r = Integer.parseInt(color[0]);
				int g = Integer.parseInt(color[1]);
				int b = Integer.parseInt(color[2]);
				fontC = new Color(r,g,b);
			}
			text = "";
			for(int i = 3; i < msgs.length ; i++){
				text = text + msgs[i];
			}
		}
		FontAndText attr = new FontAndText();
		
		attr.setName(fontName);
		attr.setSize(fontSize);
		attr.setColor(fontC);
		
		attr.setText(text);
		
		System.out.println("getRecivedFont(String message):"+attr.toString());
		return attr;
	}
	/**
	 * 插入圖片
	 * 
	 * @param isFriend 是否爲朋友發過來的消息
	 */
	int pos1;
	int pos2;
	private void insertPics(boolean isFriend) {
		
		if(isFriend){
			if(this.receivdPicInfo.size()<=0){
				return;
			}else{
				for(int i = 0 ; i < receivdPicInfo.size() ; i++){
					PicInfo pic = receivdPicInfo.get(i);
					String fileName;
					jpChat.setCaretPosition(pos1+pic.getPos()); /*設置插入位置*/
		            fileName= "qqdefaultface/"+pic.getVal()+".gif";/*修改圖片路徑*/ 
					jpChat.insertIcon(new  ImageIcon(PicsJWindow.class.getResource(fileName))); /*插入圖片*/
/*					jpChat.updateUI();*/
				}
				receivdPicInfo.clear();
			}
		}else{
			
			if(myPicInfo.size()<=0){
				return;
			}else{
				for(int i = 0 ; i < myPicInfo.size() ; i++){
					PicInfo pic = myPicInfo.get(i);
					jpChat.setCaretPosition(pos2+pic.getPos()); /*設置插入位置*/
					String fileName;
		            fileName= "qqdefaultface/"+pic.getVal()+".gif";/*修改圖片路徑*/ 
					jpChat.insertIcon(new  ImageIcon(PicsJWindow.class.getResource(fileName))); /*插入圖片*/
					/*jpChat.updateUI();*/
				}
				myPicInfo.clear();
			}
		}
		jpChat.setCaretPosition(docChat.getLength()); /*設置滾動到最下邊*/
		//insert(new FontAttrib()); /*這樣做可以換行*/
	}
	/**
	 * 將帶格式的文本插入JTextPane
	 * 
	 * @param attrib
	 */
	private void insert(FontAndText attrib) {
		try { // 插入文本
			docChat.insertString(docChat.getLength(), attrib.getText() + "\n",
					attrib.getAttrSet());
			jpChat.setCaretPosition(docChat.getLength()); // 設置滾動到最下邊
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
	}
	
	private void insert(String text) {
		try { // 插入文本
			docChat.insertString(docChat.getLength(), text + "\n",
					dateFont.getAttrSet());
			jpChat.setCaretPosition(docChat.getLength()); // 設置插入位置
			
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
	}
	/**
	 *字體屬性輔助類
	 */
	class FontAndText{
		public static final int GENERAL = 0; // 常規
		private String msg = "", name = "宋體"; // 要輸入的文本和字體名稱

		private int size = 0; //字號

		private Color color = new Color(225,225,225); // 文字顏色

		private SimpleAttributeSet attrSet = null; // 屬性集
		/**
		 * 一個空的構造(可當做換行使用)
		 */
		
		public FontAndText() {
		}
		public FontAndText(String msg,String fontName,int fontSize,Color color){
			this.msg = msg;
			this.name = fontName;
			this.size = fontSize;
			this.color = color;
		}

		/**
		 * 返回屬性集
		 * 
		 * @return
		 */
		public SimpleAttributeSet getAttrSet() {
			attrSet = new SimpleAttributeSet();
			if (name != null){
				StyleConstants.setFontFamily(attrSet, name);
			}
			StyleConstants.setBold(attrSet, false);
			StyleConstants.setItalic(attrSet, false);
			StyleConstants.setFontSize(attrSet, size);
			if (color != null)
				StyleConstants.setForeground(attrSet, color);
			return attrSet;
		}
		public String toString(){
			//將消息分爲四塊便於在網絡上傳播
			return name+"|"
			+size+"|"
			+color.getRed()+"-"+color.getGreen()+"-"+color.getBlue()+"|"
			+msg;
		}
		public String getText() {
			return msg;
		}

		public void setText(String text) {
			this.msg = text;
		}

		public Color getColor() {
			return color;
		}

		public void setColor(Color color) {
			this.color = color;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public int getSize() {
			return size;
		}

		public void setSize(int size) {
			this.size = size;
		}
	}
	/**
	 * 獲取所需要的文字設置
	 * 
	 * @return FontAttrib
	 */
	private FontAndText getFontAttrib() {
		FontAndText att = new FontAndText();
		att.setText(jpMsg.getText()+"*"+buildPicInfo());//文本和表情信息
		att.setName((String) fontName.getSelectedItem());
		att.setSize(Integer.parseInt((String) fontSize.getSelectedItem()));
		String temp_color = (String) fontColor.getSelectedItem();
		if (temp_color.equals("黑色")) {
			att.setColor(new Color(0, 0, 0));
		} else if (temp_color.equals("紅色")) {
			att.setColor(new Color(255, 0, 0));
		} else if (temp_color.equals("藍色")) {
			att.setColor(new Color(0, 0, 255));
		} else if (temp_color.equals("黃色")) {
			att.setColor(new Color(255, 255, 0));
		} else if (temp_color.equals("綠色")) {
			att.setColor(new Color(0, 255, 0));
		}
		return att;
	}
	
	private  class receivMsgThread extends Thread{/*接收在線好友和陌生人消息*/
		DatagramSocket chatSoc = null;
		public receivMsgThread(){
				try {
					chatSoc = new DatagramSocket(Sender.chatPort);
				} catch (SocketException e) {
					e.printStackTrace();
					System.exit(1);
				}
			}
			@Override
			public void run(){
				while(true){
					try {
						byte[] bytes=new byte[1024*128];
						DatagramPacket dp=new DatagramPacket(bytes, bytes.length);
						chatSoc.receive(dp);
						String recStr = new String(bytes, 0, dp.getLength(), "UTF-8");
						//System.out.println("GroupsPanel recStr = " + recStr);
						String[] strs = recStr.split("[*]");
						int msgType;
						if(strs.length>=3){
							msgType = Integer.parseInt(strs[0]);
						}else{
							/*System.out.println("不是好友發過來的聊天信息!");*/
							continue;
						}
						String uname = strs[1];

						String message = strs[2];
						if(strs.length>3){
							for(int i = 3; i < strs.length ; i++){
								message = message + "*" + strs[i];
							}
						}
						if(msgType == MsgType.CHAT){
							ChatFrame.this.addRecMsg(uname,message);

						}else if(msgType == MsgType.SHAKE){
							ChatFrame.this.shake(uname);
						}
					} catch (Exception e) {
						JOptionPane.showMessageDialog(ChatFrame.this, "系統運行出錯!");
						e.printStackTrace();
					}
				}
			}
		}
	public static void setUIFont(FontUIResource f) {
	/*	sets the default font for all Swing components.
		ex.setUIFont (new
		javax.swing.plaf.FontUIResource("Serif",Font.ITALIC,12));*/
		java.util.Enumeration keys = UIManager.getDefaults().keys();
		while (keys.hasMoreElements()) {
			Object key = keys.nextElement();
			Object value = UIManager.get(key);
			if (value instanceof FontUIResource)
				UIManager.put(key, f);
		}
	}
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException {
	/*	 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
	*/	 /*和系統的觀感保持一致*/
		 
		setUIFont(new FontUIResource("宋體", Font.PLAIN, 15));
		new ChatFrame().setVisible(true);
	}
}


CoolToolTip.java

package com.zou.chat;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
/**
 * 氣泡提示框類
 */
public class CoolToolTip extends JPanel {
 private static final long serialVersionUID = 1L;
 private JLabel label = new JLabel();
 private boolean haveShowPlace;
 private Component attachedCom; // 要顯示提示氣泡的組件
 private Component parentWindow; // 要顯示提示氣泡的組件的窗體
 public CoolToolTip(Component parent,Component attachedComponent, Color fillColor,
   int borderWidth, int offset) {
  this.parentWindow = parent;
  this.attachedCom = attachedComponent;
  label.setBorder(new EmptyBorder(borderWidth, borderWidth, borderWidth,
    borderWidth));
  label.setBackground(fillColor);
  label.setOpaque(true);
  label.setFont(new Font("system", 0, 12));

  setOpaque(false);
  // this.setBorder(new BalloonBorder(fillColor, offset));
  this.setLayout(new BorderLayout());
  add(label);

  setVisible(false);
  // 當氣泡顯示時組件移動,氣泡也跟着移動
  this.attachedCom.addComponentListener(new ComponentAdapter() {
   @Override
   public void componentMoved(ComponentEvent e) {
    if (isShowing()) {//懸浮提示 顯示了的,重新設置位置
     determineAndSetLocation();
    }
   }
  });
 }
 private void determineAndSetLocation() {
  if(!attachedCom.isShowing()){
   return;
  }
  Point loc = attachedCom.getLocationOnScreen(); //控件相對於屏幕的位置
  Point paPoint = parentWindow.getLocationOnScreen(); //對應窗體相對於屏幕的位置
  //System.out.println(attachedComponent.getLocationOnScreen());
  setBounds(loc.x-paPoint.x, loc.y -paPoint.y - getPreferredSize().height,
    getPreferredSize().width, getPreferredSize().height);
 }
 public void setText(String text) {
  label.setText(text);
 }
 // 設置氣泡背景圖片
 public void setIcon(Icon icon) {
  label.setIcon(icon);
 }
 // 設置氣泡的文字和圖片間的距離
 public void setIconTextGap(int iconTextGap) {
  label.setIconTextGap(iconTextGap);
 }
 @Override
 public void setVisible(boolean show) {
  if (show) {
   determineAndSetLocation();
   findShowPlace();
  }
  super.setVisible(show);
 }
 private void findShowPlace() {
  if (haveShowPlace) {
   return;
  }
  // we use the popup layer of the top level container (frame or
  // dialog) to show the balloon tip
  // first we need to determine the top level container
  JLayeredPane layeredPane = null;
  if(parentWindow instanceof JDialog){
   layeredPane = ((JDialog)parentWindow).getLayeredPane();
  }else if(parentWindow instanceof JFrame){
   layeredPane = ((JFrame)parentWindow).getLayeredPane();
  }
  
  /*Container parent = attachedCom.getParent();
  while (true) {
   if (parent instanceof JFrame) {
    layeredPane = ((JFrame) parent).getLayeredPane();
    break;
   } else if (parent instanceof JDialog) {
    layeredPane = ((JDialog) parent).getLayeredPane();
    break;
   }
   parent = parent.getParent();
  }*/
  if(layeredPane!=null){
   layeredPane.add(this, JLayeredPane.POPUP_LAYER);
   haveShowPlace = true;
  }
 }
 public Component getAttachedComponent() {
  return attachedCom;
 }
 public void setAttachedComponent(Component attachedComponent) {
  this.attachedCom = attachedComponent;
 }
}


Sender.java

package com.zou.chat;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Random;
public class Sender {
	/*本機ip*/
	public static String localIP = "127.0.0.1";
	/*服務器ip*/
	public static String serverIP = null;
	/*錯誤信息*/
	public static String err_msg = "";
	 /*默認發送端口*/
	public static int SendPort = 5555;
	/*默認聊天端口*/
	public static int chatPort = 6666;  
	/*接收信息的socket*/
	/*private static DatagramSocket recDs = null;*/
	/*private static DatagramSocket chatSoc = null;*/
	static{
		/*rm = new Random();*/
		/*setLocalIP();*/
		/*chatPort = generateUDPPort();*/
	}
	public Sender(){
/*		try {
			if(recDs == null){
				rePort = generateUsefulPort();
				recDs = new DatagramSocket(rePort);
			}
		} catch (SocketException e) {
			e.printStackTrace();
		}*/
		//findServer();
	}
	/**
	 * @param msgType 消息類別
	 * @param uname
	 * @param friendIP
	 * @param friendPort
	 * @return 發送是否成功
	 */
	public static boolean sendUDPMsg(int msgType,String uname,String friendIP,int friendPort,String messae){
	    try
        {
            /*從命令行得到要發送的內容,使用UTF-8編碼將消息轉換爲字節*/
            byte[] msg = (msgType+"*"+uname+"*"+messae).getBytes("UTF-8");
            /*得到主機的internet地址*/
            InetAddress address = InetAddress.getByName(friendIP);

            /*用數據和地址初始化一個數據報分組(數據包)*/
            DatagramPacket packet = new DatagramPacket(msg, msg.length, address,
            		friendPort);

            /*創建一個默認的套接字,通過此套接字發送數據包*/
            DatagramSocket dSocket = new DatagramSocket();
            dSocket.send(packet);

            /*發送完畢後關閉套接字*/
            dSocket.close();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            err_msg = "系統運行異常!";
            return false;
        }
		return true;
	}
	/**
	 * 獲取本機的IP
	 */
/*	private  static void setLocalIP(){
		try {
			InetAddress address = InetAddress.getLocalHost();
			localIP = address.getHostAddress();
		} catch (UnknownHostException e) {
			e.printStackTrace();
			err_msg = "出錯:SendMessage.takeLocalIP():Exception!";
		}
		System.out.println("localIP = " + localIP);
	}*/
	/*private static Random  rm;*/
/*	private static int generateUsefulPort(){
			int port  = 1025 + rm.nextInt(5000);
			try{   
		        bindPort("0.0.0.0", port);   
		        bindPort(InetAddress.getLocalHost().getHostAddress(),port);   
		    }catch(Exception e){   
		    	e.printStackTrace();
		        return generateUsefulPort();   
		    }  
		    System.out.println("generateUsefulPort=" + port);
		    return port;
	}*/
/*	public static int generateUDPPort(){
		rePort = 1024 + rm.nextInt(5000);
		try {
			DatagramSocket socket = new DatagramSocket(rePort);
			socket.close();
		} catch (IOException e) {
			return generateUDPPort();
		}
		return rePort;
}*/
	/**
	 * 檢測tcp端口是否可用
	 * @param host
	 * @param port
	 * @throws Exception
	 */
/*	private static void bindPort(String host, int port) throws Exception{   
        Socket s = new Socket();   
        s.bind(new InetSocketAddress(host, port));   
        s.close();
    }   */
}


MsgType.java

package com.zou.chat;
public final class MsgType {
 public final static int CHAT = 0;  //聊天
 public final static int ONLINE = 1;  //上線
 public final static int OFFLINE = 2; //下線
 public final static int SHAKE = 3;  //震動
}


運行一個後,改Sender.java,中的 端口,互換端口,運行另一個

 /*默認發送端口*/
 public static int SendPort = 5555;
 /*默認聊天端口*/
 public static int chatPort = 6666; 

如果要帶圖片的,請到我的資源中下載微笑
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章