最近做了聊天氣泡功能,為自己的聊天室美化了一下聊天效果;
先來看一下效果:
主要的思路是:以一個JTextPane作為顯示的面板,然后自定義一個組件JBubble氣泡組件來實現他的聊天氣泡,然后通過JTextPane中的insertComponent(jbubble);方法把組件添加
到JTextPane上。同時通過setCaretPosition(count);方法設置添加到末尾,count為當前以及有的組件的書目加一;
一:具體的過程:
(1)自定義JBubble組件:繼承JComponent,重寫paintComponent(Graphics g) 方法
在java中,所有的組件都是畫出來的,所以這個聊天氣泡畫出來的;具體的步驟是:
- 首先畫出發消息的人的頭像 :g.drawImage(img, x, y, width, height, observer);
- 再畫出消息箭頭 g.fillPolygon(xPoints, yPoints, nPoints):通過給定缺點的幾點來畫一個多邊形出來,第一個參數是一個是該多邊形的所有的點的X軸坐標,第二個參數是該多邊形的所有的點的Y軸的坐標,第三個點是該多邊形的點數;
- 然后在根據消息的寬度,以及高度,畫出消息矩形框:g.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
- 最后畫出文字:g.drawString(str, x, y);
在構建組件的時候需要去區分一下是自己發的消息,還是他人發的消息,這樣不同的發送方,畫的位置不一樣。
在實現這個組件中需要解決的問題是:
- 確定文字的高度和寬度
消息矩形框的高度和寬度是根據一段字符串的高度以及寬度來確定的。然后還需要考慮的是當字符串的寬度大於組件的寬度的時候我們就需要來考慮一下文字的換行問題;
在java中提供了一個FontMetrics類來可以獲取文字的大小:
FontMetrics fm = FontDesignMetrics.getMetrics(font);
int width = fm.stringWidth(message);// 獲取整個字符串的寬度
int height = fm.getHeight();//獲取字符的高度
在JBubble組件中利用了一個ArrayList來存儲以及分好行的字符串,之前用過一個String類型的數組來存儲,但是后面發現,每一個字符的寬度是不一樣的(中文與英文以及數字之間是不一樣的),所以不能夠通過整除來確定划分的字符串的長度。雖然想過通過正則表達式來區分英文以及中文,數字這樣,然后來進行分行,但最后還是選擇了一種簡單地方法;
(2) MessagePane類:實現文字和圖片的處理,然后添加到JTextPane上面
為了划分字符串,實現分行,定義了一個MessagePane來管理所有的消息氣泡;
主要的屬性是:一個JTextPane對象,以及兩個ImageICon對象來表示自己的頭像以及他人的頭像;然后兩個int,分別表示一個組件的寬度以及 JTextPane中的組件的數目;
主要的方法是:
- addTextMessage(String messages, boolean fla);添加文字消息;
換行的操作比較簡單,利用while循環來遍歷整個字符串,當一段字符串的長度大於字符的時候就存入ArrayList中;
/*** * 添加文本消息 * * @param messages * 要添加的消息 * @param fla * 是否是自己發送的消息 */ public void addTextMessage(String messages, boolean fla) { Font font = jtextpane.getFont(); // 獲取字符串的高度 int sHeight = getWordHeight(font, messages); System.out.println("字符串取得的高度為" + sHeight); // 獲取字符串的寬度 int sWidth = getWordsWidth(font, messages); System.out.println("字符串取得的寬度為" + sWidth); //存儲分行的字符串 ArrayList<String> str = new ArrayList<String>(); if (sWidth > width - 100) { // int i=0; int beginIndex=0; int endIndex=1; while( endIndex<messages.length()){ String s=messages.substring(beginIndex,endIndex); if(getWordsWidth(font, s)>(width - 100)||endIndex==messages.length()-1){ str.add(messages.substring(beginIndex,endIndex-1)); beginIndex=endIndex-1; } endIndex++; } } else str.add(messages); JBubble jbubble = new JBubble(sHeight, getWordsWidth(font,str.get(0)), str, fla); if (fla) jbubble.setUserIcon(userIcon); else jbubble.setUserIcon(otherIcon); jbubble.setPreferredSize(new Dimension(width, sHeight * (str.size() + 1) + 30)); jtextpane.insertComponent(jbubble); count++; jtextpane.setCaretPosition(count); // jtextpane.repaint(); }