【VSCode】VSCode為Java C/S項目添加圖形用戶界面

為Java C/S項目添加圖形用戶界面

現在我們來為它添加圖形用戶界面(GUI)。我將使用Java Swing庫創建一個簡單的GUI,因為它內置于Java標準庫中,無需額外依賴。

客戶端GUI實現

首先,我們將修改客戶端代碼,添加一個Swing GUI界面:

修改后的Client.java(帶GUI)

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;public class Client {private static final String SERVER_ADDRESS = "localhost";private static final int SERVER_PORT = 12345;// GUI組件private JFrame frame;private JTextField messageField;private JTextArea chatArea;private JButton sendButton;private JTextField nameField;private JButton connectButton;// 網絡連接private Socket socket;private ObjectOutputStream out;private ObjectInputStream in;private String clientName;private boolean connected = false;public static void main(String[] args) {SwingUtilities.invokeLater(() -> {try {new Client().createAndShowGUI();} catch (Exception e) {e.printStackTrace();}});}private void createAndShowGUI() {// 創建主窗口frame = new JFrame("聊天客戶端");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setSize(500, 400);frame.setLayout(new BorderLayout());// 頂部面板 - 連接信息JPanel topPanel = new JPanel(new FlowLayout());topPanel.add(new JLabel("用戶名:"));nameField = new JTextField("用戶", 10);topPanel.add(nameField);connectButton = new JButton("連接服務器");connectButton.addActionListener(e -> connectToServer());topPanel.add(connectButton);frame.add(topPanel, BorderLayout.NORTH);// 中間面板 - 聊天內容chatArea = new JTextArea();chatArea.setEditable(false);JScrollPane scrollPane = new JScrollPane(chatArea);frame.add(scrollPane, BorderLayout.CENTER);// 底部面板 - 消息輸入JPanel bottomPanel = new JPanel(new BorderLayout());messageField = new JTextField();messageField.addActionListener(e -> sendMessage());sendButton = new JButton("發送");sendButton.addActionListener(e -> sendMessage());bottomPanel.add(messageField, BorderLayout.CENTER);bottomPanel.add(sendButton, BorderLayout.EAST);frame.add(bottomPanel, BorderLayout.SOUTH);// 設置窗口可見frame.setVisible(true);}private void connectToServer() {if (connected) {appendToChat("已經連接到服務器");return;}clientName = nameField.getText().trim();if (clientName.isEmpty()) {JOptionPane.showMessageDialog(frame, "請輸入用戶名", "錯誤", JOptionPane.ERROR_MESSAGE);return;}// 在新線程中連接服務器,避免阻塞UInew Thread(() -> {try {socket = new Socket(SERVER_ADDRESS, SERVER_PORT);out = new ObjectOutputStream(socket.getOutputStream());in = new ObjectInputStream(socket.getInputStream());connected = true;SwingUtilities.invokeLater(() -> {connectButton.setText("斷開連接");appendToChat("已連接到服務器");});// 啟動接收消息的線程new Thread(this::receiveMessages).start();} catch (IOException e) {SwingUtilities.invokeLater(() -> {JOptionPane.showMessageDialog(frame, "無法連接到服務器: " + e.getMessage(), "連接錯誤", JOptionPane.ERROR_MESSAGE);});}}).start();}private void disconnect() {connected = false;try {if (out != null) out.close();if (in != null) in.close();if (socket != null) socket.close();} catch (IOException e) {e.printStackTrace();}SwingUtilities.invokeLater(() -> {connectButton.setText("連接服務器");appendToChat("已斷開與服務器的連接");});}private void sendMessage() {if (!connected) {JOptionPane.showMessageDialog(frame, "請先連接到服務器", "錯誤", JOptionPane.ERROR_MESSAGE);return;}String messageText = messageField.getText().trim();if (messageText.isEmpty()) {return;}try {Message message = new Message(clientName, messageText);out.writeObject(message);out.flush();messageField.setText("");} catch (IOException e) {appendToChat("發送消息失敗: " + e.getMessage());disconnect();}}private void receiveMessages() {try {Message message;while (connected && (message = (Message) in.readObject()) != null) {final Message finalMessage = message;SwingUtilities.invokeLater(() -> appendToChat(finalMessage.toString()));}} catch (IOException | ClassNotFoundException e) {if (connected) { // 只在仍然連接時顯示錯誤SwingUtilities.invokeLater(() -> {appendToChat("與服務器的連接已斷開");disconnect();});}}}private void appendToChat(String text) {chatArea.append(text + "\n");chatArea.setCaretPosition(chatArea.getDocument().getLength());}
}

服務器管理界面

雖然服務器通常不需要GUI,但為了方便監控,我們可以添加一個簡單的管理界面:

修改后的Server.java(帶管理界面)

import java.io.*;
import java.net.*;
import java.util.concurrent.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;public class Server {private static final int PORT = 12345;private static ExecutorService pool = Executors.newFixedThreadPool(10);private static ServerSocket serverSocket;private static boolean running = false;private static List<ClientHandler> clients = new ArrayList<>();// GUI組件private JFrame frame;private JTextArea logArea;private JButton startButton;private JButton stopButton;public static void main(String[] args) {SwingUtilities.invokeLater(() -> {try {new Server().createAndShowGUI();} catch (Exception e) {e.printStackTrace();}});}private void createAndShowGUI() {// 創建主窗口frame = new JFrame("聊天服務器");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setSize(600, 400);frame.setLayout(new BorderLayout());// 頂部面板 - 控制按鈕JPanel topPanel = new JPanel(new FlowLayout());startButton = new JButton("啟動服務器");startButton.addActionListener(e -> startServer());topPanel.add(startButton);stopButton = new JButton("停止服務器");stopButton.addActionListener(e -> stopServer());stopButton.setEnabled(false);topPanel.add(stopButton);frame.add(topPanel, BorderLayout.NORTH);// 中間面板 - 日志logArea = new JTextArea();logArea.setEditable(false);JScrollPane scrollPane = new JScrollPane(logArea);frame.add(scrollPane, BorderLayout.CENTER);// 底部面板 - 狀態信息JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));bottomPanel.add(new JLabel("客戶端數量: 0"));frame.add(bottomPanel, BorderLayout.SOUTH);// 設置窗口可見frame.setVisible(true);}private void startServer() {if (running) {appendLog("服務器已經在運行中");return;}new Thread(() -> {try {serverSocket = new ServerSocket(PORT);running = true;SwingUtilities.invokeLater(() -> {startButton.setEnabled(false);stopButton.setEnabled(true);appendLog("服務器已啟動,監聽端口: " + PORT);});while (running) {try {Socket clientSocket = serverSocket.accept();appendLog("新客戶端連接: " + clientSocket.getInetAddress());ClientHandler clientThread = new ClientHandler(clientSocket);clients.add(clientThread);pool.execute(clientThread);} catch (IOException e) {if (running) { // 只有在服務器仍在運行時才記錄錯誤appendLog("接受客戶端連接時出錯: " + e.getMessage());}}}} catch (IOException e) {appendLog("啟動服務器失敗: " + e.getMessage());}}).start();}private void stopServer() {running = false;try {if (serverSocket != null && !serverSocket.isClosed()) {serverSocket.close();}} catch (IOException e) {appendLog("關閉服務器時出錯: " + e.getMessage());}// 斷開所有客戶端連接for (ClientHandler client : clients) {client.disconnect();}clients.clear();startButton.setEnabled(true);stopButton.setEnabled(false);appendLog("服務器已停止");}private void appendLog(String text) {SwingUtilities.invokeLater(() -> {logArea.append(new Date() + " - " + text + "\n");logArea.setCaretPosition(logArea.getDocument().getLength());});}private class ClientHandler implements Runnable {private Socket clientSocket;private ObjectOutputStream out;private ObjectInputStream in;private String clientName;public ClientHandler(Socket socket) {this.clientSocket = socket;}@Overridepublic void run() {try {out = new ObjectOutputStream(clientSocket.getOutputStream());in = new ObjectInputStream(clientSocket.getInputStream());Message message;while (running && (message = (Message) in.readObject()) != null) {clientName = message.getSender(); // 記錄客戶端名稱appendLog("收到來自 " + clientName + " 的消息: " + message.getContent());// 廣播給所有客戶端broadcastMessage(message);}} catch (IOException | ClassNotFoundException e) {appendLog("客戶端 " + (clientName != null ? clientName : clientSocket.getInetAddress()) + " 斷開連接");} finally {disconnect();clients.remove(this);}}public void disconnect() {try {if (in != null) in.close();if (out != null) out.close();if (clientSocket != null) clientSocket.close();} catch (IOException e) {// 忽略關閉時的異常}}private void broadcastMessage(Message message) {for (ClientHandler client : clients) {try {client.out.writeObject(message);client.out.flush();} catch (IOException e) {appendLog("向客戶端發送消息失敗: " + e.getMessage());client.disconnect();clients.remove(client);}}}}
}

編譯和運行

  1. 重新編譯所有文件:

    javac -encoding UTF-8 -d shared/bin shared/src/Message.java
    javac -encoding UTF-8 -cp "shared/bin" -d server/bin server/src/Server.java
    javac -encoding UTF-8 -cp "shared/bin" -d client/bin client/src/Client.java
    
  2. 先運行服務器:

    java -cp "server/bin;shared/bin" Server
    
  3. 然后運行一個或多個客戶端:

    java -cp "client/bin;shared/bin" Client
    

界面功能說明

客戶端界面功能:

  1. 輸入用戶名
  2. 連接/斷開服務器按鈕
  3. 消息輸入框和發送按鈕
  4. 聊天內容顯示區域

服務器界面功能:

  1. 啟動/停止服務器按鈕
  2. 服務器日志顯示區域
  3. 顯示客戶端連接狀態

擴展建議

  1. 美化界面:使用更現代的界面風格,可以考慮使用JavaFX而不是Swing
  2. 添加更多功能
    • 用戶列表顯示
    • 私聊功能
    • 文件傳輸
    • 表情符號支持
  3. 持久化存儲:將聊天記錄保存到數據庫
  4. 用戶認證:添加登錄/注冊功能
  5. 群組聊天:支持創建和加入不同的聊天室

這個GUI版本應該能讓您的C/S項目更加用戶友好,同時保留了原有的所有功能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/94837.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/94837.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/94837.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【云原生】Docker 搭建Kafka服務兩種方式實戰操作詳解

目錄 一、前言 二、Docker 搭建kafka介紹 2.1 Docker 命令部署 2.2 使用Docker Compose 部署 2.3 使用 Docker Swarm 2.4 使用 Kubernetes 2.5 部署建議 三、Docker 搭建kafka操作方式一 3.1 前置準備 3.2 完整操作過程 3.2.1 創建docker網絡 3.2.2 啟動zookeeper容…

DBeaver中禁用PostgreSQL SSL的配置指南

在DBeaver中為PostgreSQL連接禁用SSL是一個常見的配置&#xff0c;特別是當你的數據庫服務器未啟用SSL或遇到連接問題時。我來為你詳細講解操作步驟和注意事項。 &#x1f6e0;? DBeaver中禁用PostgreSQL SSL的配置指南 詳細步驟 打開驅動設置&#xff1a;在DBeaver中創建新的…

數組去重【JavaScript】

數組去重&#xff0c;并且key和val相同的對象視為相同的&#xff0c;需要去重。主函數&#xff1a;/*** 數組去重* 兩個屬性相同的對象也認為是相同的* param {Array} arr* return {Array} */ function uniqueArray(arr) {const result []// outer: 標簽&#xff0c;標記外層循…

基于單片機設計的智能停車系統_271

文章目錄 一、前言 1.1 項目介紹 【1】項目開發背景 【2】設計實現的功能 【3】項目硬件模塊組成 【4】設計意義 【5】國內外研究現狀 【6】摘要 1.2 設計思路 1.3 系統功能總結 1.4 開發工具的選擇 【1】設備端開發 【2】上位機開發 1.5 參考文獻 1.6 系統框架圖 1.7 系統原理…

for in+邏輯表達式 生成迭代對象,最后轉化為列表 ——注意list是生成器轉化為列表,但[生成器]得到的就是一個列表,其中包含一個生成器元素

(int(digit) ** 2 for digit in str(n))這個不是 數組(list)&#xff0c;而是一個 生成器表達式 (generator expression)。它的作用是&#xff1a;str(n) 把數字 n 轉成字符串&#xff0c;例如 n 82 → "82"。for digit in str(n) 遍歷字符串中的每個字符 → "…

通信算法之321:verilog中generate if 用法-綜合掉無用分支

文章目錄 一.示例代碼 二.優缺分析 三. generate - case 一.示例代碼 提示:參考 // 根據添加/補償頻偏的標志,確定使用的頻偏wire signed [WIDTH-1 : 0] freq;generateif(FREQ_FLAG == 1b1) beg

Shell 入門

目錄 一、Shell 是什么 二、 .sh 腳本調用 .py 腳本 Python 核心邏輯腳本&#xff08;data_processor.py&#xff09; Shell 腳本&#xff08;pipeline.sh&#xff09; 三、常見命令 四、.sh腳本 1. 簡單例子 2. 進階例子 3. 猜數字游戲 一、Shell 是什么 Shell 的本…

UNet改進(36):融合FSATFusion的醫學圖像分割

1. 注意力機制的理論基礎 1.1 空間注意力機制 空間注意力機制模擬人類視覺系統,能夠關注圖像中的顯著區域。其核心思想是根據特征圖的空間位置生成權重圖,突出重要區域并抑制無關信息。常見的實現方式是通過沿通道維度的池化操作獲取空間統計信息,然后通過卷積層生成空間注…

docker安裝kafka、zookeeper詳細步驟

Kafka 簡介 Kafka 是一個分布式流處理平臺,由 LinkedIn 開發并開源,主要用于高吞吐量的實時數據管道和流處理。 核心特性 高吞吐量:支持每秒百萬級消息處理,適合大數據場景。 持久化存儲:消息可持久化到磁盤,并支持多副本備份。 分布式架構:支持水平擴展,通過分區(P…

Photoshop - Ps 編輯圖像

使用基本圖像編輯技術&#xff0c;讓圖像展現出最好的一面。1.修剪和拉直使用裁剪工具&#xff0c;可以修剪邊緣&#xff0c;更改圖像的形狀和大小&#xff0c;甚至可以對圖像進行拉直和彎曲的操作。2.改善亮度和色彩點擊菜單欄-編輯-調整-亮度/對比度&#xff0c;調整圖像的亮…

SpringBoot 配置文件在運維開發中的應用

在 SpringBoot 項目的運維開發工作里&#xff0c;配置文件相關知識是繞不開的重要內容。它關乎著項目在不同環境下的靈活部署、參數調整&#xff0c;直接影響著應用的穩定性與可維護性。接下來&#xff0c;我們就從臨時屬性、屬性加載優先順序、配置文件分類這幾個維度&#xf…

雷卯國產化之SE3401完全替代AOS的AO3401

上海雷卯PMOS型號SE3401 pin to pin替代AOS型號AO3401&#xff0c;已經有很多客戶選用 SE3401替代AO3401&#xff0c;客戶可以獲得更好的價格和更快的交期。特別是在一些受空間收下限的小電子設備很受青睞。參數對比如下&#xff1a;以下是SE3401&#xff08;P溝道MOSFET&#…

多語言與零樣本語音識別新突破:基于發音特征分類的方法

多語言與零樣本語音識別新突破:基于發音特征分類的方法 在語音識別領域,多語言和零樣本(zero-shot)語言的識別一直是一個極具挑戰性的課題。近期,京都大學的研究團隊提出了一種全新的方法,通過引入國際音標(IPA)和發音特征(Articulatory Features)來提升語音識別系統…

1.8 Memory

1.Memory簡介 2.Memory中各參數的功能和作用1.Memory簡介 1).Memory(內存)模塊它是unity中監視內存使用情況的關鍵工具, 它能幫助我們識別哪些資源在占有大量內存,是否存在內存泄露或垃圾回收頻繁等問題2).游戲中如果出現以下問題, 可以重點觀察memorya.游戲卡頓, 掉幀- 表現: …

國家統計局數據爬取——機器學習

這個代碼是一個用于爬取國家統計局網站數據的Python腳本。下面我將詳細解釋代碼的各個部分及其設計思路。 代碼結構概述 import requests # 發送HTTP請求 from bs4 import BeautifulSoup # 解析HTML import pandas as pd # 數據處理和存儲 import time # 時間控制 import…

內存管理(智能指針,內存對齊,野指針,懸空指針)

&#x1f4cc; 1. 野指針 (Wild Pointer)什么是野指針&#xff1f;野指針指的是未初始化的指針變量。它指向的內存地址是隨機的、未知的。產生原因cppint* ptr; // 野指針&#xff01;未初始化&#xff0c;指向隨機地址 *ptr 10; // 危險&#xff01;可能破壞系統內存char* st…

Spring代理的特點

一.Spring代理的特點1.依賴注入和初始化影響的是原始的對象。2.代理和目標是兩個對象&#xff0c;二者成員變量不共用數據。二.測試首先準備以下幾個類。Bean1package com.example.springdemo.demos.a13;import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.…

嵌入式學習日記(35)TCP并發服務器構建

單循環服務器&#xff1a;服務端同一時刻只能處理一個客戶端的任務并發服務器&#xff1a;服務端同一時刻可以處理多個客戶端的任務TCP并發服務器構建&#xff1a;TCP&#xff1a; 1. 建立連接&#xff0c;一對一TCP服務端并發模型&#xff1a;1. 多進程進程資源開銷大&#x…

【Flask】測試平臺開發實戰-第二篇

概述&#xff1a;在上一篇我們已經將后端初始化服務后前端的vue框架初始化已經搭建完整&#xff0c;并且可以運行看到界面&#xff0c;服務正常&#xff0c;當然我們看到的前端數據都是mock下的假數據&#xff0c;并不是真實的&#xff0c;這篇我們來開發實現第一個功能&#x…

聊一聊 .NET 的 AssemblyLoadContext 可插拔程序集

一&#xff1a;背景 1. 講故事 最近在分析一個崩潰dump時&#xff0c;發現禍首和AssemblyLoadContext有關&#xff0c;說實話這東西我也比較陌生&#xff0c;后來查了下大模型&#xff0c;它主要奔著替代 .NetFrameWork 時代的 AppDomain 的&#xff0c;都是用來做晚期加卸載&a…