views:

120

answers:

2

Hi, these are my classes.when i run my MainClient class,one frame will be shown that get text from client and then send it to the server.at the first time when i click on the Send button,it will work correctly and send data to the server but suddenly the frame will confused and I can not do any thing like writing or clicking on the button!!please help me.

MainClient class:

//these are in the main(String[] args)

MainFrame farme = new MainFrame();
farme.setVisible(true);
c = new Socket("localhost", 5050);

os = new PrintWriter(c.getOutputStream(), true);
is = new BufferedReader(new InputStreamReader(c.getInputStream()));

//this method is not in the main(String[] args)
public static void active() {

    String teXt = MainClient.getText();
    System.out.println(teXt);
    os.println(teXt);
    String line = is.readLine();
    System.out.println("Text received: " + line);
}

my gui class which get text from client and by clicking on the send button will send that text to the server:(Send button action performed)

 public ChatFrame(InformationClass client) {
    initComponents();


    jButton1.setEnabled(false);
    this.client = client;
    jTextArea2.setText("");

}

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
    submit();
    clear();
}
private void submit() {
    String text = jTextArea1.getText();

    jTextArea2.append(client.getCurrentName() + " : " + text + "\n");
    MainClient.setText(client.getCurrentName() + " : " + text + "\n");
    MainClient.active();
}

private void clear() {
    jTextArea1.setText("");
}
A: 

I'd bet your problem stems from all the IO objects you didn't close. Try flushing and closing your Reader and Writer objects.

os.Flush();
os.Close();
is.Flush();
is.Close();

Also, close your socket connection.

c.Close();
iandisme
no it doesn't work!
Johanna
+3  A: 

The MainClient.active() call is blocking waiting for the Socket to respond. Because it is called in the ActionListener it is blocking the Swing event dispatch thread on which all UI events are triggered. This is causing the UI to be unresponsive.

If you can you should use SwingWorker to perform the blocking task in a background thread. See the documentation here:

http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html

If SwingWorker is not available then you can do it with something like this:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            // This gets run in a background thread
            String text = jTextArea1.getText();
            jTextArea2.append(client.getCurrentName() + " : " + text + "\n");
            MainClient.setText(client.getCurrentName() + " : " + text + "\n");
            MainClient.active();
        }
    }).start();
}

That is an ugly way to do it but it is also the shortest and will work on any version of Java that has Swing.

Edit: The clear method has to be called on the event dispatch thread as it accesses a UI component - jTextArea1.setText(""). To make it run on the EDT do this:

SwingUtilities.invokeLater(new Runnable() { 
    @Override 
    public void run() { 
        clear();
    } 
});

Anonymous inner classes are ugly especially when they are inside other anonymous inner classes but they are convenient for code samples. In your actual implementation you should create a class that implements Runnable to do the original background task to make the code more readable.

Closures in Java 7 should make this sort of task a lot less cluttered.

Russ Hayward
nice,thanks a lot for your nice help!!!!! that was something nice for me! also I added SwingUtilities.invokeLater(Runnable) ; after MainClient.active but it will give an error that is create a Runnable parameter.would you please help me??
Johanna
You need something like this: SwingUtilities.invokeLater(new Runnable() { @Override public void run() { clear(); } });That will work but anonymous inner classes are ugly (especially when they are inside other anonymous inner classes). You should create a class that implements Runnable to do the original background task to make the code more readable. Closures in Java 7 should make this sort of task a lot less cluttered.
Russ Hayward
I have done what you told but still it doesn't clear!!! private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {new Thread(new Runnable() { @Override public void run() {String text = jTextArea1.getText();jTextArea2.append(client.getCurrentName() + " : " + text + "\n"); MainClient.setText(client.getCurrentName() + " : " + text + "\n");MainClient.active();SwingUtilities.invokeLater(new Runnable() { @Override public void run() { clear(); } }); } }).start(); }
Johanna
Ugh - that code came out even more ugly than usual in the comments. I have moved the information to the answer to make it easier to read.
Russ Hayward
I don't think your call to is.readLine() in MainClient.active is ever returning. For readLine to return a line feed character must be read from the Socket - are you sure your server is sending one? Do you get "Text received:..." printed to the console?
Russ Hayward