2013-03-23 191 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