3

I was trying a simple code in java for test, just a button when u click it it sleeps for 5 seconds, here's the handler

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)    {                                               
    try {
        System.out.println ("hiiii");
        Thread.sleep (5000);
        System.out.println ("bye");        
    } catch (InterruptedException ex) {
        Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
    }
} 

I want this button doesn't receive any events until it finishes working (5 seconds), I tried to disable and enable it in the handler but in vain

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         

    jButton1.setEnabled(false);

    try {
        System.out.println ("hiiii");
        Thread.sleep (5000);
        System.out.println ("bye");        
    } catch (InterruptedException ex) {
        Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
    }

    jButton1.setEnabled(true);
} 
  • 2
    `sleep` blocks the EDT. Use [`Timer`](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) instead. – Maroun Sep 03 '13 at 09:54
  • To overcome problems that may occur from sleeps or timers I used a delaying loops but the main problem still exist – Mohamed Yacout Sep 03 '13 at 10:17
  • 1
    @MohamedYacoutAbouSamra It still blocks the EDT. – Maroun Sep 03 '13 at 10:18
  • I just used these delays to imitate a real task doing something, but til now I can't find a solution for make button unresponsive during this task – Mohamed Yacout Sep 03 '13 at 10:21
  • 1
    This [example](http://stackoverflow.com/a/11372932/230513) disables the button and reenables it when the worker thread is done. – trashgod Sep 03 '13 at 11:38

1 Answers1

2

You have to move any long-running task (in your case it is a simple sleep call) outside the EDT (Event Dispatch Thread) - that thread is used to render UI, if you block it with some operation - you block all your UI at once.

Here is a proper example how you can disable/enable button:

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * @author Mikle Garin
 * @see http://stackoverflow.com/a/18590057/909085
 */

public class ButtonSleep
{
    public static void main ( String[] args )
    {
        JFrame frame = new JFrame ( "Custom list renderer" );

        final JButton button = new JButton ( "Make me sleep 5 seconds" );
        button.addActionListener ( new ActionListener ()
        {
            @Override
            public void actionPerformed ( ActionEvent e )
            {
                button.setEnabled ( false );
                new Thread ( new Runnable ()
                {
                    @Override
                    public void run ()
                    {
                        try
                        {
                            Thread.sleep ( 5000 );
                        }
                        catch ( InterruptedException e1 )
                        {
                            //
                        }
                        SwingUtilities.invokeLater ( new Runnable ()
                        {
                            @Override
                            public void run ()
                            {
                                button.setEnabled ( true );
                            }
                        } );
                    }
                } ).start ();
            }
        } );
        frame.add ( button );

        frame.pack ();
        frame.setLocationRelativeTo ( null );
        frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
        frame.setVisible ( true );
    }
}

Yes, it seems weird, but you have to move your operations to a separate thread (doesn't really matter which thread) and you have to execute any operations with UI (in this case - enabling/disabling button) inside the EDT - that is why i call setEnabled in invokeLater call and not inside the separate thread.

And yes, all Swing component listeners event calls are executed inside EDT from the beginning, so you are already inside EDT when you start executing your code inside actionPerformed method of your action listener - that is why you block the whole UI if you call sleep there.

Mikle Garin
  • 10,083
  • 37
  • 59
  • It worked for me, but I didn't find a reason to run setEnabled inside invokeLater as I removed it (invokeLater) and the code still working properly – Mohamed Yacout Sep 03 '13 at 11:22
  • 1
    It will work properly for a long time until your application become really big and would generate a lot of UI updates - at this point you will start noticing some strange UI behavior from time to time, sometimes your UI might even get into deadlock or throw some misterious exceptions. So i advise you to start thinking about that and writing a correct code right now, not when problems will hit you. – Mikle Garin Sep 03 '13 at 11:27