栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Java Swing GUI客户端和服务器聊天应用程序TextArea未更新

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java Swing GUI客户端和服务器聊天应用程序TextArea未更新

基本问题是,

textarea
null
,当你尝试和呼叫
updatetextarea
,这是因为
invokeLater
呼叫尚未执行,并构建了您的UI,你基本上有一个竞争条件。

Socket
在Swing中处理s 的通常方法是使用
SwingWorker

有关更多详细信息,请查看Swing和Worker线程中的并发性和SwingWorker。

您可以通过多种方式解决问题。您可以使用

SwingWorker
来从套接字读取文本并生成更新通知(通过
publish
/
process
)方法,这通常称为“观察者模式”。这很好,因为它可以使您的代码脱钩并生成更可重用的解决方案。

SocketReader

这个类所做的只是从中读取文本,

Socket
ActionEvent
从文本生成s,很简单。

public class SocketReader extends SwingWorker<Void, String> {    private List<ActionListener> actionListeners;    public SocketReader() {        actionListeners = new ArrayList<>(25);    }    public void addActionListener(ActionListener listener) {        actionListeners.add(listener);    }    public void removeActionListener(ActionListener listener) {        actionListeners.remove(listener);    }    @Override    protected Void doInBackground() throws Exception {        System.out.println("Connected to Server!");        try (DataInputStream in = new DataInputStream(SocketManager.INSTACNE.getInputStream())) { System.out.println("Before setting text area"); String serverInput = null; do {     // HANDLE INPUT PART HERE     serverInput = in.readUTF();     if (serverInput != null) {         System.out.println("Read " + serverInput);         publish(serverInput);     } } while (!serverInput.equals("/close")); System.out.println("Program closed");        }        return null;    }    @Override    protected void process(List<String> chunks) {        for (String text : chunks) { ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, text); for (ActionListener listener : actionListeners) {     listener.actionPerformed(evt); }        }    }}

SocketWriter

这个简单的将文字写入

Socket
,简单。从技术上讲,您不需要为此使用a
SwingWorker
,但是我喜欢这样的事实:取消它相对容易

public class SocketWriter extends SwingWorker<Void, Void> {    private List<String> messages;    private ReentrantLock lock;    private Condition waitCon;    public SocketWriter() {        messages = Collections.synchronizedList(new ArrayList<String>(25));        lock = new ReentrantLock();        waitCon = lock.newCondition();    }    public void write(String text) {        System.out.println("Write " + text);        messages.add(text);        try { lock.lock(); waitCon.signalAll();        } finally { lock.unlock();        }    }    @Override    protected Void doInBackground() throws Exception {        try (DataOutputStream out = new DataOutputStream(SocketManager.INSTACNE.getOutputStream())) { while (!isCancelled()) {     while (messages.isEmpty() && !isCancelled()) {         try {  lock.lock();  waitCon.await();         } finally {  lock.unlock();         }     }     List<String> cache = new ArrayList<>(messages);     messages.clear();     for (String text : cache) {         System.out.println("Send " + text);         out.writeUTF(text);     } }        }        return null;    }}

SocketManager

好的,这对我来说有点过大了,但是我想要一个的中央控制器

Socket
,您不必使用单例,您可以简单地使其成为一个简单的类,并将其引用传递给您
ChatClient
,然后传递给
SocketReader/Writer
,但是很晚了,我很懒

public enum SocketManager {    INSTACNE;    private String host = "localhost";    private int port = 1337;    private Socket socket;    public Socket open() throws IOException {        if (socket != null) { close();        }        socket = new Socket(host, port);        return socket;    }    public void close() throws IOException {        if (socket == null) { return;        }        socket.close();    }    public boolean isOpen() {        return socket != null && socket.isConnected() && !socket.isClosed() && !socket.isInputShutdown() && !socket.isOutputShutdown();    }    public InputStream getInputStream() throws IOException {        Objects.requireNonNull(socket, "Socket is not open");        return socket.getInputStream();    }    public OutputStream getOutputStream() throws IOException {        Objects.requireNonNull(socket, "Socket is not open");        return socket.getOutputStream();    }}

ChatClient

很棒,一切都很好,但是您打算如何使用它呢?

基本上,您将在中创建一个的实例,

SocketReader
SocketWriter
在中将
ChatClient
附加
ActionListener
到阅读器,并在
Jtextarea
触发时更新,然后将要发送的文本发送到
SocketWriter
,例如。

public class ChatClient extends javax.swing.Jframe {    public ChatClient() {        initComponents();        socketReader = new SocketReader();        socketReader.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) {     String text = e.getActionCommand();     textarea.append(text);     textarea.append("n");     textarea.setCaretPosition(textarea.getdocument().getLength()); }        });        socketReader.execute();        socketWriter = new SocketWriter();        socketWriter.execute();    }        @SuppressWarnings("unchecked")    // <editor-fold defaultstate="collapsed" desc="Generated Code">        private void initComponents() {        scrollPane = new javax.swing.JScrollPane();        textarea = new javax.swing.Jtextarea();        btnConnect = new javax.swing.JButton();        btnDisconnect = new javax.swing.JButton();        lblStatus = new javax.swing.JLabel();        lblShowStatus = new javax.swing.JLabel();        txtInput = new javax.swing.JTextField();        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);        setTitle("Chat Client A");        textarea.setEditable(false);        textarea.setColumns(20);        textarea.setRows(5);        textarea.setText("Welcome to the Chat Server. Type '/close' or Click 'Disconnect' to close.");        textarea.setWrapStyleWord(true);        textarea.setCaretPosition(textarea.getdocument().getLength());        scrollPane.setViewportView(textarea);        btnConnect.setText("Connect");        btnConnect.setActionCommand("btnConnect");        btnConnect.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) {     btnConnectMouseClicked(evt); }        });        btnDisconnect.setText("Disconnect");        btnDisconnect.setActionCommand("btnDisconnect");        btnDisconnect.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) {     btnDisconnectActionPerformed(evt); }        });        lblStatus.setText("Status: ");        lblShowStatus.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N        lblShowStatus.setForeground(new java.awt.Color(255, 51, 51));        lblShowStatus.setText("Disconnected");        txtInput.setToolTipText("");        txtInput.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) {     txtInputActionPerformed(evt); }        });        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());        getContentPane().setLayout(layout);        layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup()     .addContainerGap()     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)         .addComponent(scrollPane)         .addGroup(layout.createSequentialGroup()  .addComponent(btnConnect)  .addGap(18, 18, 18)  .addComponent(btnDisconnect)  .addGap(42, 42, 42)  .addComponent(lblStatus)  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)  .addComponent(lblShowStatus)  .addGap(0, 42, Short.MAX_VALUE))         .addComponent(txtInput))     .addContainerGap())        );        layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup()     .addContainerGap()     .addComponent(scrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 213, javax.swing.GroupLayout.PREFERRED_SIZE)     .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 11, Short.MAX_VALUE)     .addComponent(txtInput, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)     .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.baseLINE)         .addComponent(btnConnect)         .addComponent(btnDisconnect)         .addComponent(lblStatus)         .addComponent(lblShowStatus))     .addContainerGap())        );        pack();    }// </editor-fold>    private void btnConnectMouseClicked(java.awt.event.MouseEvent evt) {        // TODO add your handling pre here:        lblShowStatus.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N        lblShowStatus.setForeground(new java.awt.Color(0, 204, 51));        lblShowStatus.setText("Connected");        // ADD CODES FOR ConNECTING TO CHAT SERVER    }    private void btnDisconnectActionPerformed(java.awt.event.ActionEvent evt) {        // TODO add your handling pre here:        lblShowStatus.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N        lblShowStatus.setForeground(new java.awt.Color(255, 51, 51));        lblShowStatus.setText("Disconnected");        // ADD CODES FOR DISConNECTING FROM CHAT SERVER    }    private void txtInputActionPerformed(java.awt.event.ActionEvent evt) {        if (SocketManager.INSTACNE.isOpen()) { socketWriter.write(txtInput.getText());        } else { System.out.println("!! Not open");        }    }        public static void main(String args[]) {        try {  //<editor-fold defaultstate="collapsed" desc=" Look and feel setting pre (optional) ">  try {     for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {         if ("Nimbus".equals(info.getName())) {  javax.swing.UIManager.setLookAndFeel(info.getClassName());  break;         }     } } catch (ClassNotFoundException ex) {     java.util.logging.Logger.getLogger(ChatClient.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (InstantiationException ex) {     java.util.logging.Logger.getLogger(ChatClient.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (IllegalAccessException ex) {     java.util.logging.Logger.getLogger(ChatClient.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) {     java.util.logging.Logger.getLogger(ChatClient.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } //</editor-fold> SocketManager.INSTACNE.open();  java.awt.EventQueue.invokeLater(new Runnable() {     public void run() {         new ChatClient().setVisible(true);     } });        } catch (IOException ex) { ex.printStackTrace();        }        //</editor-fold>    }    private SocketWriter socketWriter;    private SocketReader socketReader;    // Variables declaration - do not modify   private javax.swing.JButton btnConnect;    private javax.swing.JButton btnDisconnect;    private javax.swing.JLabel lblShowStatus;    private javax.swing.JLabel lblStatus;    private javax.swing.JScrollPane scrollPane;    private javax.swing.Jtextarea textarea;    private javax.swing.JTextField txtInput;    // End of variables declaration        }

您会注意到,我曾

SocketManager#open
main
抱歉,错过了您的“连接”代码。我建议改为将其移至该方法;)

ChatServer

我对此没有做太多改变,但以防万一…

public class ChatServer {    public static void main(String args[]) {        int port = 1337;        try { ServerSocket server = new ServerSocket(port); String inMessage = ""; while (true) {     System.out.println("Waiting");     Socket clientA = server.accept();     System.out.println("Connected");     DataInputStream inA = new DataInputStream(clientA.getInputStream());     DataOutputStream outA = new DataOutputStream(clientA.getOutputStream());     // outA.writeUTF("Welcome to the Chat Server. Type '/close' or Click 'Disconnect' to close.");     // for testing     // BufferedReader user = new BufferedReader(new InputStreamReader(System.in));     do {         inMessage = inA.readUTF();         if (inMessage != null) {  outA.writeUTF(inMessage);         }     } while (!inMessage.equals("/close"));     clientA.close(); }        } catch (Exception ex) { ex.printStackTrace();        }    }}

通常,当客户端连接时,您将启动一个新

Thread
客户端并让它处理客户端
Socket
,但这不是我的重点。

因此,基于所有这些,您需要大量阅读,包括Java中的并发性和全部关于套接字



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/494832.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号