Socket Applet - JTextArea in a JScrollPane?

Hi, I have an applet that connects to a chat server. Strangely enough this is not actually the problem. The problem is with one of the JTextArea objects. Basically theres a panel with two text areas and a button; output, which is the text area taking up the bulk of the gui and input, which sits on an inner panel below the output area with the button along side it. Now, clearly both text areas need to scroll, the input area sits nicely inside the scrollPane no problem. But if I put the larger output area into a scrollPane the applet wont load??!?
To clarify that, when the applet initialises, it loads a panel with a text box (to input user name) and a button (to submit) into its content pane. The listener on the button creates a 'chat socket panel' (holding all the gui objects above and the socket to connect to the server) and replaces the applets content pane with it (effecting a login). When there is no scroll pane around the output text this happens, but if I put the output text inside a scroll pane the applet hangs between loading the chat socket panel and displaying it in the applets content pane.
The socket DOES connect, but the applet doesn't repaint itself.

Here is a snippet of the code from the 'chat socket panel' WITHOUT the scrollpane. This works:


class ChatPanel extends JPanel implements Runnable, ActionListener {
      
      private Socket socket;
      private BufferedReader in;
      private PrintWriter out;
      
      private String name;
      
      private JTextArea output;
      private JTextArea input;
                private JScrollPane inScroll;
      private JButton button;
      
      public ChatPanel(String n){
            
            name = n;
            
            try{
                  
                  socket = new Socket("127.0.0.1", 4444);
                  in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                  out = new PrintWriter(socket.getOutputStream(), true);
            
            }catch(IOException ioe){
                  
                  System.err.println("Could Not Established Streams:\n"+ioe.getMessage());
            }
      }
      
      
      public void run(){
            
            output = new JTextArea(14, 49);
            
            input = new JTextArea(3, 43);
            inScroll = new JScrollPane(input);
            
            
            button = new JButton("send");
            button.addActionListener(this);
            
            JPanel miniPanel = new JPanel();
            miniPanel.add(inScroll);
            miniPanel.add(button);
            
            
            JPanel panel = new JPanel();
            panel.setLayout(new GridLayout(2,1));
            panel.add(output);
            panel.add(miniPanel);
            
            add(panel);



the applet empties it's content pane, then creates this object, then adds that to its content pane. No problem


However if I add the line:      outScroll = new JScrollPane(output);

then it hangs:


                   public void run(){
            
            output = new JTextArea(14, 49);
            outScroll = new JScrollPane(output);


            input = new JTextArea(3, 43);
            inScroll = new JScrollPane(input);
            
            
            button = new JButton("send");
            button.addActionListener(this);
            
            JPanel miniPanel = new JPanel();
            miniPanel.add(inScroll);
            miniPanel.add(button);
            
            
            JPanel panel = new JPanel();
            panel.setLayout(new GridLayout(2,1));
            panel.add(outScroll);      //  <----- and of course change this accordingly
            panel.add(miniPanel);
            
            add(panel);



The chatPanel object is definately loading because the server registers a new client. The button moves to a 'pressed' state but apart from that there is no change in the gui. If i minimise the browser window and bring it back up again theres just a grey square, applet size.

I am baffled. I tried putting the text area inside a JPanel and then adding that to the scrollpane, that didn't work either.

Any help would be greatly appreciated, if any one wants to look at the entire code for applet and server just say.


Thanks

Dave
LVL 1
Dave_TolandAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

CEHJCommented:
You shouldn't be creating those gui components in run like that. Showing them -maybe ...

It's the socket code that should be running in its own thread, so you've got those two methods the wrong way around
0
Dave_TolandAuthor Commented:
The socket code is in the thread, here:

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.io.*;


public class ChatApplet extends JApplet implements ActionListener {

      
      JTextArea text;
      
      public void start(){
            
            text = new JTextArea(1, 15);
            JLabel name = new JLabel("Name: ");
            JButton go = new JButton("enter");
            JTextArea text = new JTextArea(1, 15);
            JPanel tmp = new JPanel();
            
            tmp.add(name);
            tmp.add(text);
            tmp.add(go);
            go.setPreferredSize(new Dimension(70,20));
            go.addActionListener(this);
            
            getContentPane().add(tmp);
      }
      
      public void actionPerformed(ActionEvent e){
            
            ChatPanel panel = new ChatPanel(text.getText());
            getContentPane().removeAll();
            getContentPane().add(panel);
            new Thread(panel).start();
      }
}



class ChatPanel extends JPanel implements Runnable, ActionListener {
      
      private Socket socket;
      private BufferedReader in;
      private PrintWriter out;
      
      private String name;
      
      private JTextArea output;
      private JScrollPane outScroll;
      private JTextArea input;
      private JScrollPane inScroll;
      private JButton button;
      
      public ChatPanel(String n){
            
            name = n;
            
            try{
                  
                  socket = new Socket("217.43.147.32", 4444);
                  in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                  out = new PrintWriter(socket.getOutputStream(), true);
            
            }catch(IOException ioe){
                  
                  System.err.println("Could Not Established Streams:\n"+ioe.getMessage());
            }
      }
      
      
      public void run(){
            
            
            out.println("@@name:"+name+'\u0000');
            
            output = new JTextArea(14, 49);
            //outScroll = new JScrollPane(output);
            
            input = new JTextArea(3, 43);
            inScroll = new JScrollPane(input);
            
            button = new JButton("send");
            button.addActionListener(this);
            
            JPanel miniPanel = new JPanel();
            miniPanel.add(inScroll);
            miniPanel.add(button);
            
            
            JPanel panel = new JPanel();
            panel.setLayout(new GridLayout(2,1));
            panel.add(output);
            panel.add(miniPanel);
            
            add(panel);
                  
            int i = 0;
            
            while(i != -1){
                  
                  try{
                        String lineIn = "";
                        char chr = '\u0000';
                        do{
                                    
                              i = in.read();
                              chr = (char)i;
                              if(chr != '\u0000' && i != -1 && i != '\r' && i != '\n')
                                    lineIn += chr;
                              
                        }while(chr != '\u0000' && i != -1);
                        
                        
                        if(lineIn.length() > 0)
                              output.setText(output.getText()+lineIn+'\n');

                  
                  }catch(IOException ioe){
                        
                        i = -1;
                  }
            }
                        
            output.setText(output.getText()+"\n\nServer Disconnected");
      }
      
      
      public void actionPerformed(ActionEvent e){
            
            out.println(input.getText()+'\u0000');
            input.setText("");
      }
}




Even still, it works fine without the scrollpane so that would lead me to believe that the gui objects were not affecting things.
0
CEHJCommented:
The code that makes the connection should be in a separate thread from the gui code. This is the general pattern - obviously there are things omitted:


public class ChatPanel {

      public ChatPanel(String n) {
            output = new JTextArea(14, 49);
            input = new JTextArea(3, 43);
            inScroll = new JScrollPane(input);
      }

      public void run() {
            try{
                  socket = new Socket("217.43.147.32", 4444);
                  in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                  out = new PrintWriter(socket.getOutputStream(), true);
                  StringBuffer sb = new StringBuffer();
                  char[] cbuf = new char[1 << 10]; //1KiB buffer
                  int charsRead = -1;
                  while ((charsRead = in.read()) > -1) {
                        sb.append(cbuf, 0, charsRead);
                  }
                  in.close();
                  EventQueue.invokeLater(new TextUpdater(sb.toString()));

            }catch(IOException ioe){
                  System.err.println("Could Not Established Streams:\n"+ioe.getMessage());
            }

      }
      
      class TextUpdater implements Runnable {
            private String text;
            
            public TextUpdater(String text) {
                  this.text = text;
            }
            public void run() {
                  output.setText(text);
            }
      }

}
0
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

objectsCommented:
Swing is single threaded, so if that thread is blocked you will get no gui updates.
So as you make your connection from the gui thread, the gui is unable to paint itself while the connection is being made.
Additionally you should only make changes to your gui from the event dispatch thread, not from other threads.

Here's an article discussing it, and a SwingWorkewr class that can be used to resolve the problem.
0
Dave_TolandAuthor Commented:
cehj thanks, point taken. objects thanks, however no link mate, would like to read the article. I don't understand why the thread is getting blocked just through the addition of a scrollpane, why is that? what is it about the pane? i mean the other scrollpane works fine...

0
CEHJCommented:
>>just through the addition of a scrollpane, why is that?

I would guess this is an accidental, deceptive phenomenon and the real reason is the one already given ;-)
0
Dave_TolandAuthor Commented:
CEHJ, I tried your code and although i appreciate your efforts on my behalf, it didn't actually solve the problem. Obviously I had to change it a bit to suit the applet, so have a look to see if what i've done is how you meant.

The problem seems to be, as objects stated, the fact that the applet was trying to repaint itself with an unrealized gui class that itself was being blocked by the fact that it contained the socket connection (regardless of whereabouts in the class that appeared). As stated, Swing is single threaded and once a gui is realized any other thread trying to affect it is unsafe unless executed in the event dispatching thread (the thread that handles the gui repaint), this is where the new gui's realization and the socket connection should take place (is that right objects?). Meaning that I cannot launch a gui, then create another one in another thread and add it, which itself has another thread inside. Swing is not multithreaded.

Therefore you were both right in identifying the root of the problem, although in fairness the solution was from objects.

Thankyou to both of you for your help. I'll wait for CEHJ to comment on what i've done, but i think the larger share of the points belongs to objects.

Let me know if either if you disagree with this.

Dave





this still doesn't work im afraid : (
swing is not multithreaded..



import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.io.*;


public class ChatApplet extends JApplet implements ActionListener {    //applet runs in its own thread anyway

      
      JTextArea text;
      
      public void start(){
            
            text = new JTextArea(1, 15);
            JLabel name = new JLabel("Name: ");
            JButton enter = new JButton("enter");
            text = new JTextArea(1, 15);
            JPanel tmp = new JPanel();
            
            tmp.add(name);
            tmp.add(text);
            enter.setPreferredSize(new Dimension(70,20));
            enter.addActionListener(this);
            tmp.add(enter);
            
            getContentPane().add(tmp);
      }
      
      public void actionPerformed(ActionEvent e){
            
            ChatPanel panel = new ChatPanel(text.getText());               //second thead - unsafe!
            getContentPane().removeAll();                                           //should be executed from event dispatcher
            getContentPane().add(panel);                                            //automatically realizes new gui
            new Thread(panel).start();                                                //uh oh!
      }
}



class ChatPanel extends JPanel implements Runnable, ActionListener {
      
      private Socket socket;
      private BufferedReader in;
      private PrintWriter out;
      
      private TextUpdater updater;
      private String name;
      
      private JTextArea output;
      private JScrollPane outScroll;
      private JTextArea input;
      private JScrollPane inScroll;
      private JButton button;
      
      
      public ChatPanel(String n){
            
            updater = new TextUpdater(n+" has joined");
            new Thread(updater).start();
            name = n;            
                        
            output = new JTextArea(14, 49);
            outScroll = new JScrollPane(output);
            
            input = new JTextArea(3, 43);
            inScroll = new JScrollPane(input);
            
            button = new JButton("send");
            button.addActionListener(this);
            
            JPanel miniPanel = new JPanel();
            miniPanel.add(input);
            miniPanel.add(button);
            
            
            JPanel panel = new JPanel();
            panel.setLayout(new GridLayout(2,1));
            panel.add(outScroll);
            panel.add(miniPanel);
            
            add(panel);
      }
      
      
      public void run(){
            
            try{
                  
                  socket = new Socket("localhost", 4444);
                  in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                  out = new PrintWriter(socket.getOutputStream(), true);
            
            }catch(IOException ioe){
                  
                  System.err.println("Could Not Established Streams:\n"+ioe.getMessage());
                  System.exit(-1);
            }
            
            out.println("@@name:"+name+'\u0000');
            
                  
            int i = 0;
            
            while(i != -1){
                  
                  try{
                        String lineIn = "";
                        char chr = '\u0000';
                        do{
                                    
                              i = in.read();
                              chr = (char)i;
                              if(chr != '\u0000' && i != -1 && i != '\r' && i != '\n')
                                    lineIn += chr;
                              
                        }while(chr != '\u0000' && i != -1);
                        
                        
                        if(lineIn.length() > 0)
                              updater.updateText(lineIn);

                  
                  }catch(IOException ioe){
                        
                        i = -1;
                  }
            }
                        
            updater.updateText("  --  Server Disconnected");
      }
      
      
      public void actionPerformed(ActionEvent e){
            
            out.println(input.getText()+'\u0000');
            input.setText("");
      }
      
      
      
          
     class TextUpdater implements Runnable {                     //yet another thread
          private String text;
         
          public TextUpdater(String text){
                   this.text = text;
          }
         
          public void updateText(String text) {
               this.text = text;
          }
         
          public void run() {
               output.setText(text);
          }
     }
}
0
Dave_TolandAuthor Commented:
hmm,  I started playing with event dispatching and after that still wouldn't work I decided to strip down the applet a bit to try and find the cause. It turns out the problem is replacing the content pane of the gui! However, even with using event dispatching I could not resolve the hang up....


still hangs:


import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.io.*;


public class ChatApplet2 extends JApplet implements ActionListener {
      
      
      private JLabel nameLbl;
      private JTextArea name;
      private JButton enter;
      private JPanel tmp;
      
      private JTextArea output;
      private JTextArea input;
      
      private JScrollPane outScroll;
      private JScrollPane inScroll;
      
      private JButton send;
      
      private JPanel miniPanel;
      private JPanel panel;
      
      
      
      public void init(){
            
            nameLbl = new JLabel("Name: ");
            name = new JTextArea(1, 15);
            enter = new JButton("enter");
            enter.setPreferredSize(new Dimension(70,20));
            enter.addActionListener(this);
            tmp = new JPanel();      
            
            
                        
            output = new JTextArea(14, 49);
            input = new JTextArea(3, 43);
            outScroll = new JScrollPane();            
            inScroll = new JScrollPane();
            
            send = new JButton("send");
            send.addActionListener(this);
            
            miniPanel = new JPanel();
            panel = new JPanel();
            panel.setLayout(new GridLayout(2,1));
      }
      
      
      public void start(){
            
            tmp.add(nameLbl);
            tmp.add(name);
            tmp.add(enter);
            
            setContentPane(tmp);
      }
      
      
      
      public void actionPerformed(ActionEvent e){
            
            Runnable updateGUI = new Runnable(){
                  
                  public void run(){

                        System.out.println("starting update");

                        outScroll.getViewport().add(output);
                        inScroll.getViewport().add(input);
                        
                        miniPanel.add(inScroll);
                        miniPanel.add(send);
                        
                        panel.add(outScroll);
                        panel.add(miniPanel);
                        
                        setContentPane(panel);
                  
                        System.out.println("finished update");
                  }
            };
            
            SwingUtilities.invokeLater(updateGUI);
      }
}


Both "starting update" and "finished update" are printed in the console, yet the gui hangs still.
0
CEHJCommented:
>>
as objects stated, the fact that the applet was trying to repaint itself with an unrealized gui class that itself was being blocked by the fact that it contained the socket connection (regardless of whereabouts in the class that appeared).
>>

I already explained that. It would not happen 'regardless' - it's preciely *where* it appears that causes the problem, as i explained

>>Let me know if either if you disagree with this.

I explained this to you already


After

>>getContentPane().add(panel);

You need to do

getContentPane().validate();
repaint();

but i wouldn't recommend this dynamic change of gui particularly. You'd be better using a CardLayout


"CEHJ has joined" appeared in the text area after the changes i mentioned running using appletviewer. IOW it works with the changes i mentioned
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Dave_TolandAuthor Commented:
firstly, whether the socket was in the constuctor of the panel class or in the run method made no difference.
also the panel (runnable) can be started before or after it is added to the applet content pane:

like this:
ChatPanel panel = new ChatPanel(text.getText());                          
new Thread(panel).start();              
getContentPane().removeAll();                                          
getContentPane().add(panel);


orlike this:
ChatPanel panel = new ChatPanel(text.getText());                                  
getContentPane().removeAll();                                          
getContentPane().add(panel);
new Thread(panel).start();    


so in that respect it doesn't matter (in this instance) when it is started, or where


the single underlying problem was the fact that this line wasn't in my code:

getContentPane().validate();

without this you get the hang up.


I imagine in other more intense applications the positioning and timing of the socket execution does affect the application and, moreover my application may or may not run better, cleaner, safer whatever, by employing event dispatching and/or critical positioning various code segments, yet as above the solution to my 'hang up' problem is validating the content pane of the applet.

CEHJ - my apologies and thanks. Your last answer held the solution [even if it came in a roundabout way : ) ] and that solved the underlying problem. You get the points.
Objects - sorry, as much as i appreciate your advice (especially the SwingWorker stuff) and im gratefull for that, it wasn't the solution to the problem.

I'm sorry if I've messed you both about, it's been a learning curve for me and I have learned something here today from both of you.
0
Dave_TolandAuthor Commented:
sorry, i got that wrong:


ike this:
ChatPanel panel = new ChatPanel(text.getText());                          
new Thread(panel).start();              
getContentPane().removeAll();                                          
getContentPane().add(panel);


orlike this:
ChatPanel panel = new ChatPanel(text.getText());                                  
getContentPane().removeAll();                                          
getContentPane().add(panel);
new Thread(panel).start();  



AS LONG AS..  the gui creation happens in the constructor and not the run. CEHJ - as you said where, not when
0
CEHJCommented:
8-)

>>Your last answer held the solution [even if it came in a roundabout way : ) ]

In these cases, where there are fundamental problems, i tend to advocate solving these first before specific ones are addressed.

Of course, objects' comments were also correct
0
Dave_TolandAuthor Commented:
right
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.