SitePoint Sponsor

User Tag List

Results 1 to 21 of 21
  1. #1
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Java - order of events

    i have textAreaA, a button and textAreaB and onclick i want it to take the value from a, change it, then output to b.

    I have done the above and it works but before b shows the output i want to display a progressBar and only display B's output once it has reached 100%

    This is purely visual and it works except that the output is displayed immediately.

    i have something like

    Code:
    1.Progress prog = new progress();
    2.prog.start();
    3.textAreaB.setText(text);
    Progress, when start is called, displays a progress bar, goes from 0-100%, then closes.

    How do i make it so line 3 will wait for the dialog in line 2 to close(i.e. the start() method to finish.

    PLEASE, if anyone has a suggestion id be very grateful.

  2. #2
    SitePoint Wizard silver trophy rushiku's Avatar
    Join Date
    Dec 2003
    Location
    A van down by the river
    Posts
    2,056
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    Add

    prog.start();
    prog.join();

    join() will cause the current thread to wait for the prog thread to finish.

  3. #3
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for reply but it doesn't seem to work. "cannot find symbol - method join()"

    Is join part of a package or something i have to import 1st?

  4. #4
    SitePoint Wizard silver trophy rushiku's Avatar
    Join Date
    Dec 2003
    Location
    A van down by the river
    Posts
    2,056
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    I assumed Progress was a Thread... Actually, it should be, as you called start().

    join() is a method of the Thread class.

  5. #5
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry, no, start is a method i created in the class progress

    Code:
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
     
    
    
    public class Progress {
    
        private JProgressBar bar = new JProgressBar(0, 2000);
        private ActionListener al = new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                bar.setValue(bar.getValue() + 37);
                if (bar.getValue() == bar.getMaximum()) {
                    timer.stop();
                    SwingUtilities.windowForComponent(bar).dispose();;
                    
                    
                    //bar.setIndeterminate(true);
                }
                
            }
            
        };
        private Timer timer = new Timer(100, al);
     
        public void start() {
            
            EventQueue.invokeLater(new Runnable(){
                public void run() {
                    Progress app = new Progress();
     
                    JDialog f = new JDialog();
                    f.getContentPane().add(app.bar);
                    
                    //f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    f.pack();
                    f.setLocationRelativeTo(null);
                    f.setVisible(true);
                    app.timer.start();
                    
                }
            });
          
        }
    
    }
    I then in another class call its constructor and then call start on it

    Code:
    ........................
    else if(e.getSource() ==  btnDecode)
            {
                int done;
                String newText = taEncryptedBox.getText();
                taEncryptedBox.setText("");
                Progress prog = new Progress();
                prog.start();
                //prog.join();<---- i want it to pause here to allow "prog" to finish displaying first
                taMessageBox.setText(newText);
                
            }
                ...........................
    ............
    ..........
    Thanks for help

  6. #6
    SitePoint Wizard silver trophy rushiku's Avatar
    Join Date
    Dec 2003
    Location
    A van down by the river
    Posts
    2,056
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    Okay, you're pretty close to what you want.

    Just have Progress extend Thread, rename start() to run() and make a few other changes (eg: no need for the anonymous Runnable anymore) and you'll be good to go.

  7. #7
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thankyou. I've made some changes but it says a java.lang.InterruptedException; must be caught or declared to be thrown?

  8. #8
    SitePoint Wizard silver trophy rushiku's Avatar
    Join Date
    Dec 2003
    Location
    A van down by the river
    Posts
    2,056
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    So catch it
    Code:
    try {
      code that may throw an exception
    } catch( ExceptionTypeThatCodeMayThrow e ) {
      e.printStackTrace();
    }

  9. #9
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I now have

    Code:
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class Progress extends Thread {
    
        private JProgressBar bar = new JProgressBar(0, 2000);
        private ActionListener al = new ActionListener() 
        {
            public void actionPerformed(ActionEvent evt) 
            {
                bar.setValue(bar.getValue() + 37);
                if (bar.getValue() == bar.getMaximum()) 
                {
                    timer.stop();
                    SwingUtilities.windowForComponent(bar).dispose();;
                }            
            }      
        };
        private Timer timer = new Timer(100, al);
     
        public void run()
        {        
            Progress app = new Progress();
    
            JDialog f = new JDialog();
            f.getContentPane().add(app.bar);
            
            //f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
            app.timer.start();            
        }
    }
    and i call it from here

    Code:
     if(e.getSource() ==  btnEncode)
            {
               .......
                Progress prog = new Progress();
                prog.run(); 
                try
                {
                    prog.join();
                }
                catch(InterruptedException ea)
                {
                    Thread.currentThread().interrupt();
                }
               
                ......
                
                
            }]
    This is all that's wrong with my code now. It now compiles and runs after adding a try catch BUT still doesn't wait, it simply displays the result before the progress bar has finished.

  10. #10
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Anyone ANY ideas?

  11. #11
    SitePoint Wizard silver trophy rushiku's Avatar
    Join Date
    Dec 2003
    Location
    A van down by the river
    Posts
    2,056
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    I was surprised it didn't work, so I wrote up a test of concept.

    Code:
    public class ThreadJoinTest_01 {
      
      private boolean joinTask = true;
    
      public static void main( String[] args ) {
        new ThreadJoinTest_01();
      }
      
      public ThreadJoinTest_01() {
        LongTask task = new LongTask();
        task.start();
        if( joinTask ) {
          try {
            task.join();
          } catch( InterruptedException e ) {
            e.printStackTrace();
          }
        }
        System.out.println( "Main thread complete" );
      }
    }
    
    class LongTask extends Thread {
    
      private boolean joinSecond = true;
    
      public void run() {
        System.out.println( "Starting LongTask" );
        try {
          sleep( 2000 );
          SecondTask second = new SecondTask();
          second.start();
          if( joinSecond ) {
            second.join();
          }
        } catch( InterruptedException e ) {
          e.printStackTrace();
        }
        System.out.println( "LongTask complete" );
      }
    }
    
    class SecondTask extends Thread {
      public void run() {
        System.out.println( "Starting SecondTask" );
        try {
          sleep( 2000 );
        } catch( InterruptedException e ) {
          e.printStackTrace();
        }
        System.out.println( "SecondTask complete" );
      }
    }
    Your problem turns out to be that your Progress thread instantiates another thread, which must also be joined to get the order of operations you're after.

    As is, my code will output:
    Starting LongTask
    Starting SecondThread
    SecondThread complete
    LongTask complete
    Main thread complete

    I put in two flags to turn the joins on and off, try each and see what happens.

    Also, call start() on threads you create, never run().

  12. #12
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thankyou for your help. I'm quite new to java.... so I have another thread? Are some things threads by nature then?

  13. #13
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    the only thing i could guess was a thread was the progress bar as start was called.

    Code:
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    /**Progress Class used to create a progress bar
     * @see ActionListener
     */
        public class Progress extends Thread 
        {
        
        private JProgressBar bar = new JProgressBar(0, 2000);
        
        private ActionListener al = new ActionListener() 
        {
            public void actionPerformed(ActionEvent evt) 
            {            
                bar.setValue(bar.getValue() + 37);
                
                
                if (bar.getValue() == bar.getMaximum()) 
                {
                    timer.stop();
                    SwingUtilities.windowForComponent(bar).dispose();;  
                }
            }  
        };
        
        /**Represents a new instance of a timer object
         */
        private Timer timer = new Timer(100, al);
        
        /**Method creates and starts the displaying of the progressbar within a dialogbox
         * 
         */
        public void run()
        { 
            Progress pb = new Progress();
            JDialog display = new JDialog();
            display.add(pb.bar);
            display.pack();
            display.setLocationRelativeTo(null);
            display.setVisible(true);
             
            try
            {
                pb.timer.start();
                pb.join();
            }
            catch(InterruptedException ea)
            {
                Thread.currentThread().interrupt();
            }
        }
    }
    So my progress class now looks like that, with

    Code:
    Progress prog = new Progress();
                     prog.start();
                    try
                    {
                        prog.join();
                    }
                    catch(InterruptedException ea)
                    {
                        Thread.currentThread().interrupt();
                    }
                    
                    taEncryptedBox.setText(convertToDisplay(encoded));
                    memory = encoded;
    to call it.

    Or would you recommend i change the code more drastically? I know Swing elements don't like sleep though, i've been told they stop it refreshing? - which ended up it being recoded the above way.

  14. #14
    SitePoint Wizard silver trophy rushiku's Avatar
    Join Date
    Dec 2003
    Location
    A van down by the river
    Posts
    2,056
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    You had me stumped for a while there...which was my fault, I misread your code.

    Here's the thing, you're instantiating a Progress in your main and calling start(), which calls run() (behind the scenes), fine so far, which subsequently instantiates another Progress, (not so fine) which it, thankfully, doesn't try to start. (starting a Progress in Progress.run() would currently cause a never ending loop of creating and starting Progresses).

    So, lose the pb in Progress.run(), you don't need it.

    Given that, and the fact that Timer is not a thread, you also don't need to call join from within Progress.

    moving on

    You have
    if (bar.getValue() == bar.getMaximum())
    but also
    bar.setValue(bar.getValue() + 37);

    No multiple of 37 is == 2000, so your condition will never be met, use >= instead.

  15. #15
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thankyou for your help. I hope none of the below make me sound ungrateful or anything like that as i appreciate the help and also know very little. However....

    Quote Originally Posted by rushiku View Post
    Here's the thing, you're instantiating a Progress in your main and calling start(), which calls run() (behind the scenes), fine so far, which subsequently instantiates another Progress, (not so fine) which it, thankfully, doesn't try to start. (starting a Progress in Progress.run() would currently cause a never ending loop of creating and starting Progresses).
    I don't have a start() in my new code(latest post)

    Quote Originally Posted by rushiku View Post
    So, lose the pb in Progress.run(), you don't need it.
    that made it worse. i tried it several ways and it doesn't work

    Quote Originally Posted by rushiku View Post
    You have
    if (bar.getValue() == bar.getMaximum())
    but also
    bar.setValue(bar.getValue() + 37);
    THis code works. The object does "dispose" itself after it has has finished executing.

    My code works 99%. All the actions happen as they should, just I have

    Text taken from TextArea A,
    Progress Bar start
    Text put into TextArea B,
    Progress bar finish

    When i want

    Text taken from TextArea A,
    Progress Bar start
    Progress bar finish
    Text put into TextArea B,

    I know this code is a little beyong my ability, just trying to stretch my capabilites and get it working then i can examine and understand it.

    Thankyou rushiku, once again for all your help (and patience).

  16. #16
    SitePoint Wizard silver trophy rushiku's Avatar
    Join Date
    Dec 2003
    Location
    A van down by the river
    Posts
    2,056
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    You really don't need 2 Progresses to get this done...

    Did you you try
    Code:
        public void run()
        { 
            JDialog display = new JDialog();
            display.add(bar);
            display.pack();
            display.setLocationRelativeTo(null);
            display.setVisible(true);
            timer.start();
        }
    ?

    Whoever wrote JProgressBar saved your butt on the == vs >= issue as values greater than the set maximum are ignored. (in JProgressBar, with max == 2000, 1999 + 37 = 2000)

    It is a bad practice to rely on things like this. When setting up a condition where you want to know if something that is being incremented has reached a certain level, always use >=, this way, you don't overshoot and keep going (forever).

    "I don't have a start() in my new code(latest post)"
    "(not so fine) which it, thankfully, doesn't try to start."

    "My code works 99&#37;. All the actions happen as they should"
    Many Rube Goldberg contraptions also work.

    The three Ss of programming:
    Simplify, simplify, simplify.

  17. #17
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by rushiku View Post

    Did you you try
    Code:
        public void run()
        { 
            JDialog display = new JDialog();
            display.add(bar);
            display.pack();
            display.setLocationRelativeTo(null);
            display.setVisible(true);
            timer.start();
        }
    Thankyou, this does simplify the code alot but still same problem. I did start with 100% of my own code but it's been changed alot.

    Thanks for help, appreciate these concepts are probably quite basic but I have only been looking at java in free time for last.... 3 months

  18. #18
    SitePoint Wizard silver trophy rushiku's Avatar
    Join Date
    Dec 2003
    Location
    A van down by the river
    Posts
    2,056
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    Okay, we weren't getting anywhere with me trying to help by treating symptoms, so I wrote a program to replicate your program, based on your description of it.

    We would have never gotten were you wanted to go if we had continued in the direction I was going...

    What I've found out is that, yes, there are threads being spawned, but no, there's no way for you to get to them such that you can join them. So that throws out the whole 'join thread' idea.

    What finally worked for me was to use a 'callback'. Technically, there are no 'real' callbacks in Java, so what I did, I feel, was in the spirit of callbacks without really being one. (a callback is when you pass a pointer to a function (C/C++ term for methods) to another object, which then calls the function at an appropriate time, there are no method pointers in Java, hence, no callbacks)

    On to the details

    In actionPerformed for my button listener, I copy the text from field a, clear the field, and start the progress class. This is important: when I create the progress class, I pass a this reference into the constructor, this gives the progress class access to the button listener (now the progress' 'parent').

    The progress class needs this access so that when the bar hits the maximum, it can call the method I added to the button listener, which will place the copied text into field b.

    As the method is not called until the progress bar has completed, the text will not appear until after the progress bar goes away.

    If you don't follow me or would prefer to see the code, let me know and I'll post it.

  19. #19
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You are very helpful. Thankyou. Would you mind posting the code so i can have a look?

  20. #20
    SitePoint Wizard silver trophy rushiku's Avatar
    Join Date
    Dec 2003
    Location
    A van down by the river
    Posts
    2,056
    Mentioned
    0 Post(s)
    Tagged
    1 Thread(s)
    Code:
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class ProgressText {
      
      public JTextField textFieldA = new JTextField( "Some Text" );
      public JTextField textFieldB = new JTextField();
      public JButton button = new JButton( "Copy" );
      
      public static void main( String[] args ) {
        new ProgressText();
      }
      
      public ProgressText() {
        JFrame frame = new JFrame();
        frame.addWindowListener( new WindowAdapter() {
          public void windowClosing( WindowEvent e ) { System.exit( 0 ); }
          //public void windowDeactivated( WindowEvent e ) { System.exit( 0 ); }
        });
        
        frame.setLayout( new GridLayout( 3, 1 ) );
        
        button.addActionListener( new ButtonListener( this ) );
        
        frame.add( textFieldA );
        frame.add( textFieldB );
        frame.add( button );
        
        frame.pack();
        frame.setVisible( true );
    
      }
    }
    
    /**
     * Using an interface allows us to decouple the Progress class from
     * the ButtonListener class
     */
    interface CompletionListener {
      public void actionCompleted();
    }
    
    /**
     * Implement the CompletionListener interface...
     */
    class ButtonListener implements ActionListener, CompletionListener {
      ProgressText parent;
      String text;
      
      public ButtonListener( ProgressText parent ) {
        this.parent = parent;
      }
      
      public void actionPerformed( ActionEvent event ) {
        text = parent.textFieldA.getText();
        
        parent.textFieldA.setText( "" );
        
        // pass a reference of this class to the Progress constructor,
        // which is expecting to receive a CompletionListener
        Progress progress = new Progress( this );
        
        progress.start();
      }
      
      public void actionCompleted() {
        parent.textFieldB.setText( text );
      }
    }
    
    class Progress extends Thread {
      
      private JProgressBar bar = new JProgressBar( 0, 20 );
      CompletionListener parent;
      
      // Store the reference to the CompletionListener
      public Progress( CompletionListener parent ) {
        this.parent = parent;
      }
      
      private ActionListener actionListener = new ActionListener() {
        public void actionPerformed( ActionEvent event )  {            
          bar.setValue( bar.getValue() + 1 );
          if( bar.getValue() >= bar.getMaximum() )  {
            timer.stop();
            SwingUtilities.windowForComponent( bar ).dispose();
            
            // call the CompletionListener.actionCompleted method
            parent.actionCompleted();
          }
        }
      };
      
      public Timer timer = new Timer( 25, actionListener );
      
      public void run() { 
        JDialog display = new JDialog();
        display.add( bar );
        display.pack();
        display.setLocationRelativeTo( null );
        display.setVisible( true );
        timer.start();
      }
    }
    Not necessarily The Right Way(tm), I'm not happy with passing the main class reference to the button listener, for instance, but it works.

  21. #21
    SitePoint Zealot
    Join Date
    Feb 2006
    Posts
    159
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thankyou. It is very much appreciated.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •