我們的項(xiàng)目采用了和騰訊QQ一樣的設(shè)計(jì)界面,擁有和騰訊QQ同等優(yōu)秀的產(chǎn)品設(shè)計(jì)理念和思路。

1.1這是我們的登錄界面





1.2注冊(cè)賬號(hào)與找回賬" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營(yíng)銷資訊 > 網(wǎng)站運(yùn)營(yíng) > java+Oracle+SWT制作簡(jiǎn)單的聊天室

java+Oracle+SWT制作簡(jiǎn)單的聊天室

時(shí)間:2023-07-22 07:42:01 | 來源:網(wǎng)站運(yùn)營(yíng)

時(shí)間:2023-07-22 07:42:01 來源:網(wǎng)站運(yùn)營(yíng)

java+Oracle+SWT制作簡(jiǎn)單的聊天室:

1.產(chǎn)品展示

按照互聯(lián)網(wǎng)行業(yè)的慣例,先吹牛。

我們的項(xiàng)目采用了和騰訊QQ一樣的設(shè)計(jì)界面,擁有和騰訊QQ同等優(yōu)秀的產(chǎn)品設(shè)計(jì)理念和思路。

1.1這是我們的登錄界面







1.2注冊(cè)賬號(hào)與找回賬號(hào)界面







1.3用戶主界面







1.4添加好友界面



1.5單聊界面(分為和機(jī)器人與真人,左邊貼了一張圖,不方便展示)













1.6群聊界面













2.細(xì)節(jié)?。?!talk is cheap,show me the code

2.1主頁面

2.1.1注冊(cè)表記住密碼

/*** 注冊(cè)表實(shí)現(xiàn)記住密碼,注冊(cè)表在我們的電腦里面,用鍵值對(duì)的方式存取*/ Preferences pre = Preferences.userNodeForPackage(getClass()); // 注冊(cè)表實(shí)現(xiàn)記住密碼 pre = Preferences.userNodeForPackage(UserLoginUI.class); pre.put(text_uname.getText(), text_pwd.getText());//存放密碼 pre.get(text_uname.getText(), null)//根據(jù)鍵獲取密碼





2.1.2界面布局







//自定義拖拽事件開始 private int startX;// 記錄鼠標(biāo)移動(dòng)前的X坐標(biāo) private int startY;// 記錄鼠標(biāo)移動(dòng)前的y坐標(biāo) private int lastX;// 記錄鼠標(biāo)移動(dòng)后的x坐標(biāo) private int lastY;// 記錄鼠標(biāo)移動(dòng)后的y坐標(biāo) private boolean isdown;// 記錄鼠標(biāo)是否按下 UserMainUI thisOBJ = this;// 實(shí)現(xiàn)窗口拖拉 自己創(chuàng)建自己這個(gè)類 /** * 設(shè)置指定區(qū)域label_topimage窗口移動(dòng)事件,你要在那個(gè)組件上添加拖拽事件就在那里添加,我這里是在label里添加的 */ label_topimage.addMouseListener(new MouseAdapter() { @Override public void mouseDown(MouseEvent e) { thisOBJ.isdown = true; thisOBJ.startX = e.x; thisOBJ.startY = e.y; } @Override public void mouseUp(MouseEvent e) { thisOBJ.isdown = false; super.mouseUp(e); } }); label_topimage.addMouseMoveListener(new MouseMoveListener() { @Override public void mouseMove(MouseEvent arg0) { if (thisOBJ.isdown) { thisOBJ.lastX = arg0.x; thisOBJ.lastY = arg0.y; int x = thisOBJ.lastX - thisOBJ.startX; int y = thisOBJ.lastY - thisOBJ.startY; org.eclipse.swt.graphics.Point location = shell.getLocation(); int xx = location.x; int yy = location.y; shell.setLocation(x + xx, y + yy); } } });





2.1.3用戶主頁采用的堆棧式布局StackLayout

主頁我們采用的是堆棧式布局,這樣就能配合自定義的label按鈕的點(diǎn)擊事件呈現(xiàn)切換界面的效果

SWT里的Composite面板為我們提供了六種布局方式,分別是

StackLayout堆棧式布局,他是所有的子面板都在堆疊在父面板上,可以通過父面板選在在最上面的那塊,但只能看到堆在最上面的那塊,可以設(shè)計(jì)觸發(fā)事件改變最上面的面板達(dá)到切換界面的效果







private StackLayout stackLayoutne;// 堆棧式布局// 采用堆棧式布局 stackLayoutne = new StackLayout(); composite_down.setLayout(stackLayoutne); // 將備選的三塊面板層疊放到composite_down主面板下 composite_tree = new Composite_tree(composite_down, SWT.NONE, fromQQ); composite_message = new Composite_message(composite_down, SWT.NONE, fromQQ); composite_weChat = new Composite_weChat(composite_down, SWT.NONE); stackLayoutne.topControl = composite_message;// 將composite_message聊天面板設(shè)置為主面板 FormData fd_composite_down = new FormData(); fd_composite_down.bottom = new FormAttachment(0, 673); fd_composite_down.right = new FormAttachment(0, 379); fd_composite_down.top = new FormAttachment(0, 222); fd_composite_down.left = new FormAttachment(0); composite_down.setLayoutData(fd_composite_down); composite_down.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));//事件里面切換面板label_center_center.addMouseListener(new MouseAdapter() { @Override public void mouseDown(MouseEvent e) { lblNewLabel_center_left.setImage(SWTResourceManager.getImage(UserMainUI.class, "/images/消息_不亮.png")); label_center_center.setImage(SWTResourceManager.getImage(UserMainUI.class, "/images/聯(lián)系人_亮.png")); label_center_right.setImage(SWTResourceManager.getImage(UserMainUI.class, "/images/空間_不亮.png")); stackLayoutne.topControl = composite_tree;// 將composite_message聊天面板設(shè)置為主面板 composite_down.layout();// 重置布局,刷新界面 } });

2.1.4用戶主界面里的子面板采用SWT自帶的滑動(dòng)面板ScrolledComposite







這樣就可以在以面板為父類的組件增長(zhǎng)時(shí)自動(dòng)產(chǎn)生滾動(dòng)條,如果嫌ScrolledComposite太丑不好看的話,可以自己寫一個(gè)子類繼承ScrolledComposite,重寫里面的方法




2.1.5其他界面

其他界面基本上是自定義的Composite,每次用的時(shí)候new一個(gè),并通過構(gòu)造函數(shù)傳遞參數(shù)進(jìn)去







樹狀結(jié)構(gòu):




//設(shè)置滾動(dòng)面板 ScrolledComposite scrolledComposite = new ScrolledComposite(this, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); scrolledComposite.setBounds(0, 0, 380, 496); scrolledComposite.setExpandHorizontal(true); scrolledComposite.setExpandVertical(true); Composite composite_1 = new Composite(scrolledComposite, SWT.NONE); composite_1.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE)); composite_1.setLayout(new RowLayout(SWT.VERTICAL));// 先將面板設(shè)置成行式布局RowLayout,再設(shè)置為VERTICAL垂直增長(zhǎng) composite_1.setSize(composite_1.computeSize(SWT.DEFAULT, SWT.DEFAULT)); scrolledComposite.setContent(composite_1); // 這一行代碼至關(guān)重要,關(guān)于自動(dòng)增長(zhǎng)序列,每次判斷下是不是超出設(shè)定好的大小,超出了自動(dòng)設(shè)置滑動(dòng)條 scrolledComposite.setMinSize(composite_1.computeSize(SWT.DEFAULT, SWT.DEFAULT));//這里值得注意的是,如果是動(dòng)態(tài)增長(zhǎng)Composite里的組件,想要自動(dòng)增長(zhǎng)滾動(dòng)條必須每次刷新后判斷 //-----------------<!--自動(dòng)增長(zhǎng)組件的代碼--!>------------------------------------------------------------------ composite_1.layout();// 重置布局,刷新界面 // 超級(jí)注意?。?!必須重置頁面再判斷是否增長(zhǎng)滾動(dòng)條,否則會(huì)出現(xiàn)無法及時(shí)增長(zhǎng)滾動(dòng)條的異常 // 這一行代碼至關(guān)重要,關(guān)于自動(dòng)增長(zhǎng)序列,每次判斷下是不是超出設(shè)定好的大小,超出了設(shè)置滑動(dòng)條 scrolledComposite_chat.setMinSize(composite_1.computeSize(SWT.DEFAULT, SWT.DEFAULT));eclipse里面組件太多了,網(wǎng)上的資料也很分散不系統(tǒng),可以看看這本書——>《Eclipse SWT/JFACE 核心應(yīng)用》 清華大學(xué)出版社

2.2Socket編程與多線程

建立實(shí)時(shí)的通訊軟件有很多常用的模式,例如同步阻塞IO(JAVA BIO)、同步非阻塞IO(Java NIO) 、異步阻塞IO(Java NIO)、(Java AIO(NIO.2))異步非阻塞IO,由于臨近期末考試,筆者也是邊學(xué)邊用,所以用的是最簡(jiǎn)單也是在業(yè)務(wù)層次最不成熟的方案同步阻塞IO(JAVA BIO),關(guān)于這些模式B站上面有個(gè)很好的課程,黑馬程序員-Java的IO模式講解(AIO&BIO&NIO),期考完后我會(huì)去好好看的哈哈哈,我這里寫的也很簡(jiǎn)單,通俗易懂,當(dāng)然問題也還有很多

2.2.1Socket編程

我這里采用的是TCP協(xié)議,總體的思路是每個(gè)客戶端只需要跟服務(wù)器進(jìn)行聊天,不對(duì)用戶產(chǎn)生點(diǎn)對(duì)點(diǎn)的聊天,由服務(wù)器充當(dāng)中介的角色進(jìn)行消息的轉(zhuǎn)發(fā)。每個(gè)客戶端在連接服務(wù)器的時(shí)候會(huì)先發(fā)送一條消息,通過自己寫的簡(jiǎn)單協(xié)議將自己的fromQQ,對(duì)方的toQQ和消息message以及信號(hào)值傳遞過去,其中信號(hào)值flag用來判斷用戶是想進(jìn)行單聊群聊還是和機(jī)器人聊天,代碼里面寫的都很詳細(xì),大家可以看看,有問題多多指出一起學(xué)習(xí)哈

package com.fx.net;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Scanner;import com.yc.util.YcUtil;import com.yc.util.fxNetUtil;/** * 采用TCP協(xié)議的服務(wù)器,設(shè)計(jì)思路為當(dāng)有用戶連接上服務(wù)器時(shí), * 用一個(gè)map將其socket存起來,key為用戶qq號(hào),為群聊時(shí),將群聊里所有用戶的socket存在list里面 * * @author fx * @time 2021年6月30日08:44:25 * */public class ServiceDemo { /** * 分別用map和qunliao存放不同連接的scoket對(duì)象 */ static Map<String, Socket> map = new HashMap<String, Socket>();// 用來存放單人聊天的fromQQ和其socket對(duì)象 // 用來放不同對(duì)象的map,包含一組socket對(duì)象 static volatile List<Socket> list = new ArrayList<Socket>();//用volatile修飾可以使其他線程實(shí)時(shí)獲取到這個(gè)變量 public static void main(String[] args) { // 服務(wù)器 // 創(chuàng)建一個(gè)服務(wù)器 System.out.println("++++++++++++++++++++"); System.out.println("騰迅QQ服務(wù)器啟動(dòng)"); System.out.println("++++++++++++++++++++"); System.out.println("服務(wù)器啟動(dòng),時(shí)間:" + new SimpleDateFormat("yyyy年MM月dd日HH:mm").format(new Date())); // 各種對(duì)象用以連接 Scanner inScanner = null; ServerSocket ss = null; Socket socket = null; String message;// 記錄客戶端發(fā)送過來的協(xié)議消息 try { ss = new ServerSocket(9999);//占有并開放端口 while (true) { // 創(chuàng)建一個(gè)接收連接客戶端的對(duì)象 9999為開放的端口 socket = ss.accept(); String ip_port = new String(socket.getRemoteSocketAddress().toString()).split("/")[1]; System.out.println("有客戶端聯(lián)接上來了,它是:" + ip_port); // 首先要接受客戶端發(fā)到的第一句話,包含fromQQ,toQQ,message和flag信號(hào)值 inScanner = new Scanner(socket.getInputStream());// 接受收入流里的字節(jié)流 message = inScanner.nextLine();//這樣接收消息高效且簡(jiǎn)單 if ("0".equals(YcUtil.objToString(fxNetUtil.getflag(message)))) { // 判斷為與機(jī)器人聊天 new Thread(new ServiceThread(socket)).start();// new一個(gè)機(jī)器人的線程與用戶交流 } else if ("1".equals(YcUtil.objToString(fxNetUtil.getflag(message)))) { // 判斷為單聊,先將socket對(duì)象存到map中 map.put(fxNetUtil.getfromQQ(message), socket); // 查找其聊天對(duì)象是否在線上,在線上應(yīng)存在socket對(duì)象 if (map.containsValue(map.get(fxNetUtil.gettoQQ(message)))) { // 存在,即通過兩個(gè)好友的socket對(duì)象進(jìn)行聊天 new Thread(new ServiceThreadsingleChat(map.get(fxNetUtil.gettoQQ(message)), map.get(fxNetUtil.getfromQQ(message)))).start(); } if (map.size() == 2) { // 當(dāng)有兩個(gè)用戶建立連接后,清空map,為后面用戶騰出空間 map.clear(); } } else if ("2".equals(YcUtil.objToString(fxNetUtil.getflag(message)))) { // 判斷為群聊,先將此時(shí)訪問的用戶qq和其socket對(duì)象存儲(chǔ)起來 list.add(socket); // 每個(gè)用戶進(jìn)入群聊都開啟一個(gè)線程進(jìn)行監(jiān)控,但list對(duì)象共享 new Thread(new ServiceThreadWechat(message, socket)).start(); } } } catch (IOException e) { e.printStackTrace(); } finally {// 關(guān)閉所有資源 if (null != socket) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if (null != ss) { try { ss.close(); } catch (IOException e) { e.printStackTrace(); } } } }}

2.2.2接入圖靈機(jī)器人API,進(jìn)行機(jī)器人聊天

代碼是網(wǎng)上東拼西湊的,我就截取來一下爬取到數(shù)據(jù)里面的有效字段,其他的也搞不懂

package com.fx.http;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.net.URL;import java.net.URLConnection;import java.net.URLDecoder;import java.net.URLEncoder;import java.util.List;import java.util.Map;/** * @Author fx * @Date 2021年7月1日09:20:25 */public class HttpTest { static String url = null; static String param = ""; public static String GetUrl(String question) { if (null == question) { question = "衡陽天氣怎么樣"; } url = "http://api.jisuapi.com/iqa/query?appkey=62958a3a6ef3c56d&question=" + encode(question); String result = "";// 訪問返回結(jié)果 BufferedReader read = null;// 讀取訪問結(jié)果 try { // 創(chuàng)建url URL realurl = new URL(url + "?" + param); // 打開連接 URLConnection connection = realurl.openConnection(); // 設(shè)置通用的請(qǐng)求屬性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 建立連接 connection.connect(); // 獲取所有響應(yīng)頭字段 Map<String, List<String>> map = connection.getHeaderFields(); read = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); String line;// 循環(huán)讀取 while ((line = read.readLine()) != null) { result += line; } } catch (Exception e) { e.printStackTrace(); } finally { if (read != null) {// 關(guān)閉流 try { read.close(); } catch (Exception e) { e.printStackTrace(); } } } // 截取需要的有效字符 return new String(result).split("/"content/":/"")[1].split("/",/"relquestion/"")[0]; } /** * Unicode編碼 * * @param url * @return */ public static String encode(String url) { try { String encodeURL = URLEncoder.encode(url, "UTF-8"); return encodeURL; } catch (UnsupportedEncodingException e) { return "Issue while encoding" + e.getMessage(); } } /** * Unicode解碼 * * @param url * @return */ public static String decode(String url) { try { String prevURL = ""; String decodeURL = url; while (!prevURL.equals(decodeURL)) { prevURL = decodeURL; decodeURL = URLDecoder.decode(decodeURL, "UTF-8"); } return decodeURL; } catch (UnsupportedEncodingException e) { return "Issue while decoding" + e.getMessage(); } }}


其他的問題暑假再一一完善叭,倉庫里面的代碼有很多試錯(cuò)時(shí)候留下的初期版本,沒時(shí)間去掉了?。?!寫了半個(gè)月,現(xiàn)在要好好準(zhǔn)備期末考試了

這篇文章我首先是寫在我的筆記本上的,哪里寫的詳細(xì)一點(diǎn),這里是搬運(yùn)過來的

我的筆記:

源碼地址:



關(guān)鍵詞:簡(jiǎn)單

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點(diǎn)擊下載Chrome瀏覽器
關(guān)閉