|
| |
The solution to this problem is to cause long-running work to be done in a
separate thread.
Here is a version of the above program that solves the
problem:
package noHangThread;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
/**
* This is a frame which solves the problems associated with trying to
* do large amounts of work from within the Event Dispatch Thread.
*/
public class NoHangThreadExample extends JFrame
{
//Construct the applet
public NoHangThreadExample()
{
setTitle("No Hang Thread Example");
setSize(200, 200);
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add( new ButtonPanel(), BorderLayout.CENTER );
contentPane.add(m_progressLabel, BorderLayout.SOUTH);
}
private void doWork()
{
setProgress(false, "Working...");
try
{
Thread.sleep(10000); // represents a long operation of some kind.
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}
setProgress(true, "Done");
}
private void setProgress(final boolean enableButton, final String text)
{
SwingUtilities.invokeLater( new Runnable()
{
public void run()
{
m_clickMeButton.setEnabled(enableButton);
m_progressLabel.setText(text);
}
}
);
}
class ButtonPanel extends JPanel implements ActionListener
{
ButtonPanel()
{
setBackground(Color.blue);
m_clickMeButton.addActionListener(this);
add(m_clickMeButton);
m_nowClickMeButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent ev)
{
ButtonPanel.this.setBackground(Color.yellow);
}
}
);
m_nowClickMeButton.setEnabled(false); // Disable for now
add(m_nowClickMeButton);
}
public void actionPerformed(ActionEvent ev)
{
setBackground(Color.red);
m_nowClickMeButton.setEnabled(true);
Thread thread = new Thread()
{
public void run()
{
doWork();
}
};
thread.start();
}
}
public static void main(String[] args)
{
NoHangThreadExample frame = new NoHangThreadExample();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private JButton m_clickMeButton = new JButton("Click me!");
private JButton m_nowClickMeButton = new JButton("Now try to click me!");
private JLabel m_progressLabel = new JLabel(" ", SwingConstants.CENTER);
}
|
Note that the only change is to invoke doWork() from a separate thread.
Try It!
Here is an applet that invokes the above code when you click on its
"Start" button:
|
|
Again, after you've brought the JFrame up, try clicking on the "Click me!"
button, and see what actually happens! |
Results
Did you notice that, now:
- The "Click me!" button "springs back" immediately?
- The background color changes to red immediately?
- The "Now try to click me!" button is now enabled immediately?
- The whole GUI does not freeze?
|