Solved

Socket Applet - JTextArea in a JScrollPane?

Posted on 2004-10-29
580 Views
Last Modified: 2013-11-23
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
0
Question by:Dave_Toland
    14 Comments
     
    LVL 86

    Expert Comment

    by:CEHJ
    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
     
    LVL 1

    Author Comment

    by:Dave_Toland
    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
     
    LVL 86

    Expert Comment

    by:CEHJ
    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
     
    LVL 92

    Expert Comment

    by:objects
    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
     
    LVL 1

    Author Comment

    by:Dave_Toland
    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
     
    LVL 86

    Expert Comment

    by:CEHJ
    >>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
     
    LVL 92

    Expert Comment

    by:objects
    0
     
    LVL 1

    Author Comment

    by:Dave_Toland
    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
     
    LVL 1

    Author Comment

    by:Dave_Toland
    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
     
    LVL 86

    Accepted Solution

    by:
    >>
    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
     
    LVL 1

    Author Comment

    by:Dave_Toland
    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
     
    LVL 1

    Author Comment

    by:Dave_Toland
    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
     
    LVL 86

    Expert Comment

    by:CEHJ
    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
     
    LVL 1

    Author Comment

    by:Dave_Toland
    right
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Prepare to Pass the CompTIA A+ 900 Series Exam

    CompTIA aims to adapt its A+ Certification to reflect the most current knowledge and skills needed by today's IT professionals--and this year's 2016 exam is harder than ever. This certification is one of the most highly-respected and sought after in IT.

    Suggested Solutions

    Introduction Java can be integrated with native programs using an interface called JNI(Java Native Interface). Native programs are programs which can directly run on the processor. JNI is simply a naming and calling convention so that the JVM (Java…
    Introduction This article is the second of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers the basic installation and configuration of the test automation tools used by…
    Viewers will learn about if statements in Java and their use The if statement: The condition required to create an if statement: Variations of if statements: An example using if statements:
    The viewer will learn how to implement Singleton Design Pattern in Java.

    913 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    18 Experts available now in Live!

    Get 1:1 Help Now