Java-項目-001-多人聊天帶界面(界面利用可視化swt)

Java-項目-001-多人聊天帶界面(界面利用可視化swt)-2020-6-25

零、操作效果

在這裏插入圖片描述

一、ClientApp.java


import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Text;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList; //用於存儲客戶信息
import java.util.StringTokenizer; //引入 StringTokenizer 類,用於信息分離
import java.net.*;
import java.io.*;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.List;

public class ClientApp {
	List clientsList;// 用戶列表
	Socket socket = null;
	BufferedReader cin = null;
	PrintStream cout = null;
	String clientName = "";
	Label L1, L2, L3;
	Button connectServer, send, disconnect;
	// 連接服務器按鈕、發送信息按鈕、斷開連接按鈕
	Text ipAddress, textPort, textClientName, talkMessage, textAreaMessage;
	// IP地址輸入框、端口輸入框、用戶名輸入框、聊天信息輸入框、聊天信息顯示區
	protected Shell shell;

	/**
	 * Launch the application.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			ClientApp window = new ClientApp();
			window.open();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Open the window.
	 */
	public void open() {
		Display display = Display.getDefault();
		createContents();
		shell.open();
		shell.layout();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
	}

	/**
	 * Create contents of the window.
	 */
	protected void createContents() {
		shell = new Shell();
		shell.setSize(930, 550);
		shell.setText("簡單聊天系統-客戶端");
		// shell.setFont(SWTResourceManager.getFont("宋體", 14, SWT.NORMAL));

		L1 = new Label(shell, SWT.NONE);
		// L1.setFont(SWTResourceManager.getFont("宋體", 14, SWT.NORMAL));
		L1.setBounds(10, 15, 120, 40);
		L1.setText("服務器IP");

		L2 = new Label(shell, SWT.NONE);
		// L2.setFont(SWTResourceManager.getFont("宋體", 14, SWT.NORMAL));
		L2.setBounds(282, 15, 60, 40);
		L2.setText("端口");

		L3 = new Label(shell, SWT.NONE);
		// L3.setFont(SWTResourceManager.getFont("宋體", 14, SWT.NORMAL));
		L3.setBounds(471, 15, 120, 40);
		L3.setText("客戶名稱");

		ipAddress = new Text(shell, SWT.BORDER);
		// ipAddress.setFont(SWTResourceManager.getFont("宋體", 13, SWT.NORMAL));
		ipAddress.setText("127.0.0.1");
		ipAddress.setBounds(126, 14, 140, 40);

		textPort = new Text(shell, SWT.BORDER);
		// textPort.setFont(SWTResourceManager.getFont("宋體", 13, SWT.NORMAL));
		textPort.setText("4321");
		textPort.setBounds(345, 14, 120, 40);

		talkMessage = new Text(shell, SWT.BORDER);
		// talkMessage.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
		// talkMessage.setFont(SWTResourceManager.getFont("宋體", 11, SWT.NORMAL));
		talkMessage.setText("");
		talkMessage.setBounds(10, 90, 484, 90);

		textAreaMessage = new Text(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
		textAreaMessage.setEditable(false);
		// textAreaMessage.setFont(SWTResourceManager.getFont("宋體", 11, SWT.NORMAL));
		// textAreaMessage.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
		textAreaMessage.setBounds(282, 204, 616, 280);

		textClientName = new Text(shell, SWT.BORDER);
		// textClientName.setFont(SWTResourceManager.getFont("宋體", 13, SWT.NORMAL));
		textClientName.setBounds(597, 10, 110, 45);
		clientsList = new List(shell, SWT.BORDER);
		// clientsList.setFont(SWTResourceManager.getFont("宋體", 11, SWT.NORMAL));
		clientsList.setBounds(22, 204, 244, 280);
	
		
		connectServer = new Button(shell, SWT.NONE);
		// connectServer.setForeground(SWTResourceManager.getColor(SWT.COLOR_DARK_CYAN));
		// connectServer.setFont(SWTResourceManager.getFont("宋體", 14, SWT.NORMAL));
		connectServer.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				try {
					InetAddress ip = InetAddress.getByName(ipAddress.getText());
					int port = Integer.parseInt(textPort.getText());
					socket = new Socket(ip, port);
					textAreaMessage.append("系統提示:與聊天服務器系統開始連接......\n");
				} catch (IOException e1) {
					textAreaMessage.append("服務器端口打開出錯\n");
				}
				if (socket != null) {
					textAreaMessage.append("系統提示:與服務器連接成功......\n");
					clientName = textClientName.getText().trim();
					try {
						cin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
						cout = new PrintStream(socket.getOutputStream());
						String str = "PEOPLE:" + clientName;
						cout.println(str);
						ReadMessageThread readThread = new ReadMessageThread();
						readThread.start();
					} catch (IOException e3) {
						textAreaMessage.append("輸入輸出異常\n");
					}
				}
			}
		});
		connectServer.setBounds(726, 15, 172, 40);
		connectServer.setText("連接服務器");
		send = new Button(shell, SWT.NONE);
		// send.setForeground(SWTResourceManager.getColor(SWT.COLOR_DARK_CYAN));
		// send.setFont(SWTResourceManager.getFont("宋體", 14, SWT.NORMAL));
		send.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				String str = talkMessage.getText();
				str = "MSG:" + clientName + ":" + str;
				cout.println(str);
			}
		});
		send.setBounds(500, 100, 200, 40);
		send.setText("發送信息");
		disconnect = new Button(shell, SWT.NONE);
		// disconnect.setForeground(SWTResourceManager.getColor(SWT.COLOR_DARK_CYAN));
		// disconnect.setFont(SWTResourceManager.getFont("宋體", 14, SWT.NORMAL));
		disconnect.setBounds(726, 100, 172, 40);
		disconnect.setText("\u65AD\u5F00\u8FDE\u63A5");
		disconnect.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				String str = "QUIT";
				cout.println(str);
				textAreaMessage.append("客戶請求斷開連接\n");
			}
		});

	}

	class ReadMessageThread extends Thread {
		boolean isRun = true;

		public void list(final ArrayList<String> imessage) {
			Display.getDefault().syncExec(new Runnable() {
				public void run() {
					clientsList.removeAll();
					for (String temp : imessage)
						clientsList.add(temp);
				}
			});
		}

		public void appendTextArea(String str) {
			final String str1 = str;
			Display.getDefault().syncExec(new Runnable() {
				public void run() {
					textAreaMessage.append(str1);
				}
			});
		}

		public void run() {
			String line = "";
			while (isRun) {
				try {
					line = cin.readLine();// 從端口讀入一條信息
				} catch (IOException e) {
					this.appendTextArea("輸入輸出異常\n");
				}
				StringTokenizer st = new StringTokenizer(line, ":");
				String keyword = st.nextToken();// 存儲關鍵字,判斷消息類型
				if (keyword.equalsIgnoreCase("QUIT")) {
					try {
						socket.close();
						this.appendTextArea("接收到服務器同意斷開信息,套接字關閉\n");
					} catch (IOException e) {
						this.appendTextArea("套接字關閉異常\n");
					}
					isRun = false;
				} else if (keyword.equalsIgnoreCase("PEOPLE")) {
					ArrayList<String> imessage = new ArrayList<String>();
					while (st.hasMoreTokens())
						imessage.add(st.nextToken());
					this.list(imessage);
				} else {
					// 接收的是來自服務器的廣播信息
					// 將信息的餘下內容全部提取,並去掉首字符(冒號),並顯示
					String message = st.nextToken("\0");
					message = message.substring(1);
					this.appendTextArea(message + "\n");
				}
			}
		}
	}
}

二、ServerApp.java


import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Label;

import java.net.*;
import java.io.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList; //引入 ArrayList 類,用於存儲客戶信息
import java.util.StringTokenizer; //引入 StringTokenizer 類,用於信息分離
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.custom.ScrolledComposite;

import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

public class ServerApp {
	ServerSocket server = null;// server成員變量的作用是用來打開服務器的端口
	ConnectSocket connect = null;
	static ArrayList<Client> clients = new ArrayList<Client>();
//	Socket socket = null;// socket成員變量的作用是用來與客戶端建立套接字連接
//	BufferedReader cin = null;// cin成員變量的作用是用來建立輸入流
//	PrintStream cout = null;// cout成員變量的作用是用來建立輸出流
	Label label;
	Text textPort;//端口輸入框
	Button actionListener;//監聽按鈕
	Text connectionArea, notificationArea;//已連接用戶列表、信息顯示框
	protected Shell shell;

	/**
	 * Launch the application.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			ServerApp window = new ServerApp();
			window.open();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Open the window.
	 */
	public void open() {
		Display display = Display.getDefault();
		createContents();
		shell.open();
		shell.layout();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
	}

	/**
	 * Create contents of the window.
	 */
	protected void createContents() {
		shell = new Shell();
		shell.setSize(680, 515);
		shell.setText("簡單聊天系統-服務端");
		//shell.setFont(SWTResourceManager.getFont("宋體", 14, SWT.NORMAL));

		Label label = new Label(shell, SWT.NONE);
		//label.setFont(SWTResourceManager.getFont("宋體", 15, SWT.NORMAL));
		label.setBounds(52, 9, 118, 50);
		label.setText("\u76D1\u542C\u7AEF\u53E3");

		textPort = new Text(shell, SWT.BORDER);
		//textPort.setFont(SWTResourceManager.getFont("宋體", 13, SWT.NORMAL));
		textPort.setBounds(194, 10, 200, 60);
		textPort.setText("4321");

		actionListener = new Button(shell, SWT.NONE);
		//actionListener.setForeground(SWTResourceManager.getColor(SWT.COLOR_LIST_SELECTION));
		//actionListener.setFont(SWTResourceManager.getFont("宋體", 14, SWT.NORMAL));
		actionListener.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				try {
					// 打開服務器端口
					server = new ServerSocket(Integer.parseInt(textPort.getText()));
					notificationArea.append("系統提示:聊天服務器系統開始啓動...... \n");
				} catch (IOException e1) { // 捕捉可能產生的異常
					notificationArea.append("服務器端口打開出錯\n");
				}
				if (server != null) {
					/* 開始用戶連接 */
					ConnectSocket connect = new ConnectSocket();
					connect.start();
				}
			}
		});
		actionListener.setBounds(440, 10, 200, 60);
		actionListener.setText("開始監聽");

		connectionArea = new Text(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
		//connectionArea.setFont(SWTResourceManager.getFont("宋體", 11, SWT.NORMAL));
		//connectionArea.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
		connectionArea.setBounds(20, 90, 620, 164);
		connectionArea.setEditable(false);

		notificationArea = new Text(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
		//notificationArea.setFont(SWTResourceManager.getFont("宋體", 11, SWT.NORMAL));
		//notificationArea.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
		notificationArea.setBounds(20, 270, 620, 179);
		notificationArea.setEditable(false);
	}

	


	public boolean checkName(Client newClient) {
		for (int i = 0; i < clients.size(); i++) {
			// 取出每一個連接對象元素
			Client c = (Client) clients.get(i);
			// 如果不是對象自身但名字相同,則表明出現了重複名稱
			if ((c != newClient) && (c.name).equals(newClient.name))
				return false;
		}
		return true;
	}

	public void notifyRoom() {
		// 服務器發送到客戶的信息字符串,“PEOPLE”表示是客戶列表信息
		String people = "PEOPLE";
		for (int i = 0; i < clients.size(); i++) {
			// 獲取每一個服務器—客戶交互信息線程
			Client c = (Client) clients.get(i);
			// 將用戶名稱添加到發送信息字符串
			people += ":" + c.name;
		}
		// 調用信息廣播成員方法,將用戶列表信息發送到所有客戶端
		sendClients(people);
	}

	public void sendClients(String msg) {
		for (int i = 0; i < clients.size(); i++) {
			// 獲取每一個服務器—客戶交互信息線程
			Client c = (Client) clients.get(i);
			// 通過線程的發送方法將信息發送出去
			c.send(msg);
		}
	}

	public void disconnect(Client c) {
		try {
			Display.getDefault().syncExec(new Runnable() {

				public void run() {

					// 需要操作的ui線程的代碼
					connectionArea.append(c.name + "斷開連接\n");
				}

			});
			
			// 向客戶發送斷開信息
			c.send("QUIT");
			clients.remove(c);
			c.socket.close();// 斷開連接
		} catch (IOException e) {
			notificationArea.append("客戶斷開錯誤\n");
		}
	}
	class Client extends Thread {
		String name; // 用來存儲客戶的連接姓名
		BufferedReader dis; // 用於實現接受從客戶端發送來的數據流
		PrintStream ps; // 用來實現向客戶端發送信息的打印流
		Socket socket; // 用於建立套接字
		boolean isRun = true;// 控制 Client 線程運行狀態
		// 採用異步方式更新主界面中的圖形組件

		public void appendConnectionArea(String str) {
			final String str1 = str;
			Display.getDefault().syncExec(new Runnable() {
				public void run() {
					connectionArea.append(str1);
				}
			});
		}

		
		
		public Client(Socket s) { // Client 線程的構造器
			socket = s; // 將服務器-客戶端建立連接所形成的套接字傳遞到該線程
			try {
				// 存儲特定客戶 socket 的輸入流,接受客戶發送到服務器端的信息
				dis = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				// 存儲特定客戶的輸出流,發送服務器信息給客戶*/
				ps = new PrintStream(socket.getOutputStream());
				// 讀取接收到的信息,該信息爲客戶登陸信息
				String info = dis.readLine();
				// 將信息用":"分離
				StringTokenizer stinfo = new StringTokenizer(info, ":");
				// 用 head 存儲關鍵區分字
				String head = stinfo.nextToken();
				// 第二個數據段是客戶的名稱
				name = stinfo.nextToken();
				connectionArea.append("系統消息:" + name + "已經連接\n");
			} catch (IOException e) {
				notificationArea.append("系統消息:用戶連接出錯\n");
			}
		}

		// 實現向客戶端發送信息的方法
		public void send(String msg) {
			ps.println(msg);
			ps.flush();
		}

		// 讀取客戶端發送過來的信息
		public void run() {
			while (isRun) {
				String line = null;
				try {
					/* 讀取客戶端發送的信息 */
					line = dis.readLine();
				} catch (IOException e) {
					// 如果出錯,則要關閉連接,並更新客戶列表信息
					appendConnectionArea("系統消息:讀客戶信息出錯");
					disconnect(this);
					notifyRoom();
					return;
				}
				// 對讀入的信息進行分離,以確定信息類型
				StringTokenizer st = new StringTokenizer(line, ":");
				String keyword = st.nextToken();// 關鍵字,判斷消息類型
				if (keyword.equalsIgnoreCase("MSG")) {
					/*
					 * 將接收到的客戶聊天信息,通過調用信息廣播成員方法, 發送到所有客戶端
					 */
					sendClients(line);
					// 如果關鍵字是 QUIT,則是客戶端發送的退出信息
				} else if (keyword.equalsIgnoreCase("QUIT")) {
					// 發送同意斷開信息到客戶端
					send("QUIT");
					// 關閉連接,並更新客戶列表信息
					disconnect(this);
					notifyRoom();
					// 結束當前線程
					isRun = false;
				}
			}
		}
	}
	class ConnectSocket extends Thread {
		public void appendInformation() {
			Display.getDefault().syncExec(new Runnable() {
				public void run() {
					Client c = new Client(socket);
					clients.add(c);
					if (checkName(c)) {
						c.start();
						notifyRoom();
					} else {
						disconnect(c);
					}
				}
			});
		}

		Socket socket;

		public void run() {
			while (true) {
				while (true) {
					try {
						socket = server.accept();
					} catch (IOException e2) {
						connectionArea.append("客戶連接失敗\n");
					}
					this.appendInformation();
				}
			}
		}
	}

}

三、test.java

public class test {
	public static void main(String[] args) {
		try {
			ClientApp window = new ClientApp();
			window.open();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章