2013-03-23 250 views
1

我正在嘗試學習網絡編程。我被授予使用java swing創建單線程客戶端服務器聊天應用程序的任務。我在更新GUI時遇到問題。我已經採取了textarea來顯示消息和另一個textarea來發送消息。有一個按鈕,您可以點擊發送消息。我正在使用計時器每5秒更新一次GUI。應用程序運行GUI最初更新,然後屏幕凍結。誰能幫我?我想知道我哪裏出錯了。Java單線程聊天應用程序

package chattingapplication; 

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.swing.Timer; 

/** 
* 
* @author Qanita 
*/ 
public class ServerMessenger extends javax.swing.JFrame { 
    private int port; 
    private ServerSocket server; 
    private Socket client; 
    private BufferedReader clientMessage; 
    private PrintWriter serverMessage; 
    private Timer timer; 
    private ActionListener updateDisplay; 
    private String receivingMessage; 
    private String sendingMessage; 

/** 
* Creates new form ServerMessenger 
*/ 
public ServerMessenger() { 
    initComponents(); 
    port = 13; 
    try { 
     server = new ServerSocket(port); 
     client = null; 
     client = server.accept(); 
     clientMessage = new BufferedReader(new InputStreamReader(client.getInputStream())); 
     serverMessage = new PrintWriter(client.getOutputStream(), true); 
     updateDisplay = new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent evt) { 
       receiveMessage(); 
       displayClientMessage(); 
       System.out.println("\nin timer"); 
      } 
     }; 
     timer = new Timer(5000, updateDisplay); 
     timer.setRepeats(true); 
     timer.start(); 
    } 
    catch (Exception e) { 
     System.err.println(e); 
    } 
} 

private void displayClientMessage() 
{ 
    if (receivingMessage != null) 
    { 
     receivingMessage = "\nClient : " + receivingMessage; 
     displayArea.setText(displayArea.getText() + receivingMessage); 
    } 
} 
private void displayServerMessage() 
{ 
    sendingMessage = "\nServer : " + sendingMessage; 
    displayArea.setText(displayArea.getText() + sendingMessage); 
} 
private void sendMessage() 
{ 
    sendingMessage = writingArea.getText(); 
    serverMessage.println(sendingMessage); 
} 
private void receiveMessage() 
{ 
    try { 
     receivingMessage = clientMessage.readLine(); 
    } catch (IOException ex) { 
     Logger.getLogger(ServerMessenger.class.getName()).log(Level.SEVERE, null, ex); 
    } 
} 

/** 
* This method is called from within the constructor to initialize the form. 
* WARNING: Do NOT modify this code. The content of this method is always 
* regenerated by the Form Editor. 
*/ 
@SuppressWarnings("unchecked") 
// <editor-fold defaultstate="collapsed" desc="Generated Code">       
private void initComponents() { 

    jScrollPane2 = new javax.swing.JScrollPane(); 
    displayArea = new javax.swing.JTextArea(); 
    jScrollPane1 = new javax.swing.JScrollPane(); 
    writingArea = new javax.swing.JTextArea(); 
    enter = new javax.swing.JButton(); 

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 
    setTitle("Server"); 
    setResizable(false); 

    displayArea.setEditable(false); 
    displayArea.setColumns(20); 
    displayArea.setLineWrap(true); 
    displayArea.setRows(5); 
    jScrollPane2.setViewportView(displayArea); 

    writingArea.setColumns(20); 
    writingArea.setRows(5); 
    jScrollPane1.setViewportView(writingArea); 

    enter.setText("Send"); 
    enter.addActionListener(new java.awt.event.ActionListener() { 
     public void actionPerformed(java.awt.event.ActionEvent evt) { 
      enterActionPerformed(evt); 
     } 
    }); 

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 
    getContentPane().setLayout(layout); 
    layout.setHorizontalGroup(
     layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
     .addComponent(jScrollPane2) 
     .addGroup(layout.createSequentialGroup() 
      .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 186, javax.swing.GroupLayout.PREFERRED_SIZE) 
      .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 
      .addComponent(enter, javax.swing.GroupLayout.PREFERRED_SIZE, 61, javax.swing.GroupLayout.PREFERRED_SIZE) 
      .addGap(0, 0, Short.MAX_VALUE)) 
    ); 
    layout.setVerticalGroup(
     layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
     .addGroup(layout.createSequentialGroup() 
      .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 420, Short.MAX_VALUE) 
      .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 
      .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) 
       .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) 
       .addComponent(enter, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE))) 
    ); 

    pack(); 
}// </editor-fold>       

private void enterActionPerformed(java.awt.event.ActionEvent evt) {          
    sendMessage(); 
    writingArea.setText(""); 
    displayServerMessage(); 
}          

/** 
* @param args the command line arguments 
*/ 
public static void main(String args[]) { 
    /* Set the Nimbus look and feel */ 
    //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> 
    /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. 
    * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
    */ 
    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(ServerMessenger.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
    } catch (InstantiationException ex) { 
     java.util.logging.Logger.getLogger(ServerMessenger.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
    } catch (IllegalAccessException ex) { 
     java.util.logging.Logger.getLogger(ServerMessenger.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
    } catch (javax.swing.UnsupportedLookAndFeelException ex) { 
     java.util.logging.Logger.getLogger(ServerMessenger.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
    } 
    //</editor-fold> 

    /* Create and display the form */ 
    java.awt.EventQueue.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
      new ServerMessenger().setVisible(true); 
     } 
    }); 
} 
// Variables declaration - do not modify      
private javax.swing.JTextArea displayArea; 
private javax.swing.JButton enter; 
private javax.swing.JScrollPane jScrollPane1; 
private javax.swing.JScrollPane jScrollPane2; 
private javax.swing.JTextArea writingArea; 
// End of variables declaration     

}

客戶端類與細微的差別幾乎邏輯相同。但邏輯幾乎相同。我想這個問題是與計時器有關,但是我無法弄清楚究竟是什麼問題。任何有關這方面的幫助將高度讚賞。

+2

使用SwingWorker,否則所有輸出到Swing GUI的都必須封裝到invokeLater – mKorbel 2013-03-23 17:09:28

+0

我不知道這是否已經發布過。我搜索了,我找不到解決我的問題。如果有人認爲像這樣的問題已經發布之前,然後plzzz提供了它的鏈接。 – 2013-03-23 17:11:20

+2

如果你需要它單線程,那麼甚至不能使用定時器。 – Ankit 2013-03-23 17:11:36

回答

1

BufferedReader.readLine()在內部調用java.io.Reader.read(char [],int,int)。因此與Reader.read javadoc:「此方法將阻止,直到有些輸入可用」。

您應該凍結,因爲updateDisplay()調用receiveMessage(),它調用readLine()並且沒有數據可用。

+0

現在我該怎麼做?任何其他方式,你會建議嗎? – 2013-03-23 17:32:54

+0

@QanitaZakir:你應該使用後臺線程來進行阻塞和讀取,然後更新Swing線程上的Swing GUI。這是唯一有意義的解決方案。 – 2013-03-23 17:42:59