Hey i just need a question answered...
How would i make the following code not freeze my whole JFrame?
try {
Thread.sleep(Integer.parseInt(delayField.getText()) * 1000);
System.out.println("Hello!");
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
use a different thread to perform this task. If you do this in the main UI thread then it will freeze.. For example you can do following
new Thread() {
#Override
public void run() {
try {
Thread.sleep(Integer.parseInt(delayField.getText()) * 1000);
System.out.println("Hello!");
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}.start();
UPDATE
AFter wise suggestions of Robin and Marko I am updating the answer with a better solution.
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println("Hello!");
}
};
javax.swing.Timer t = new javax.swing.Timer(Integer.parseInt(delayField.getText()) * 1000, taskPerformer);
t.setRepeats(false);
t.start();
Whenever you are about to use Thread.sleep in your GUI code, stop yourself and think of Swing Timer, which is the right tool for the job. Schedule the task you need to perform with a delay.
Using another thread for this is not the best advice: it wastes a heavy system resource (a thread) to do absolutely nothing but wait.
This is not the correct way to use threads in java . You should use swingutilities.invokelater
swing utils invoke later
You don't want to execute this on the UI (or event dispatch thread) thread. Rather in a separate thread. Otherwise (as you've seen) you'll block the UI.
It's a good practice to perform time-consuming operations on a separate thread, and make use of SwingUtilities.invokeLater() if those threads need to perform some subsequent UI action (e.g. in the above display "Hello" in the UI)
Related
Currently in my brief time with Java I have made a clicker game and I've been trying to implement a way to add a number to an integer (or the int command) every couple of seconds. but whatever I try just stops the entire program completely such as the
Thread.sleep(15000);
wait(15000);
even if they are in a try and catch it just stops the program and not complete a loop every couple of seconds.
If you have Thread.sleep(xxx); in the current thread, then yes, it will stop the current thread for xxx seconds. Because (most likely) Thread.sleep is in the same thread that is controlling the GUI, it is pausing your code from executing, freezing your application. There are two ways you can fix this:
Create a new thread and place the timer code in there:
SwingUtilities.invokeLater will add your Runnable to the queue of threads that AWT executes.
// Because the code is in a different thread, Thread.sleep(1000) will not pause
// the current thread and the application will continue as normal
Thread thread = new Thread(new Runnable() {
int seconds = 0;
#Override
public void run()
{
while (true) {
// wait one second
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
};
// increment seconds
seconds++;
System.out.println(seconds);
}
}
});
thread.start();
Use an existing timer in the Java API
Look at ScheduledThreadPoolExecutor and its scheduleAtFixedRate method. Here's an example. You could also use a swing timer as mentioned in the comment by Hovercraft Full Of Eels.
To use a Swing timer, you import javax.swing.Timer (not java.util.Timer), create a Timer object with the delay and an action listener listening for when it will fire events, and start it.
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent a)
{
System.out.println("Timer went off!");
}
});
// Repeat every second
timer.start();
Note that this code won't execute on its own; you need to have a GUI running.
Hey i just need a question answered...
How would i make the following code not freeze my whole JFrame?
try {
Thread.sleep(Integer.parseInt(delayField.getText()) * 1000);
System.out.println("Hello!");
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
use a different thread to perform this task. If you do this in the main UI thread then it will freeze.. For example you can do following
new Thread() {
#Override
public void run() {
try {
Thread.sleep(Integer.parseInt(delayField.getText()) * 1000);
System.out.println("Hello!");
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}.start();
UPDATE
AFter wise suggestions of Robin and Marko I am updating the answer with a better solution.
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println("Hello!");
}
};
javax.swing.Timer t = new javax.swing.Timer(Integer.parseInt(delayField.getText()) * 1000, taskPerformer);
t.setRepeats(false);
t.start();
Whenever you are about to use Thread.sleep in your GUI code, stop yourself and think of Swing Timer, which is the right tool for the job. Schedule the task you need to perform with a delay.
Using another thread for this is not the best advice: it wastes a heavy system resource (a thread) to do absolutely nothing but wait.
This is not the correct way to use threads in java . You should use swingutilities.invokelater
swing utils invoke later
You don't want to execute this on the UI (or event dispatch thread) thread. Rather in a separate thread. Otherwise (as you've seen) you'll block the UI.
It's a good practice to perform time-consuming operations on a separate thread, and make use of SwingUtilities.invokeLater() if those threads need to perform some subsequent UI action (e.g. in the above display "Hello" in the UI)
Hey i just need a question answered...
How would i make the following code not freeze my whole JFrame?
try {
Thread.sleep(Integer.parseInt(delayField.getText()) * 1000);
System.out.println("Hello!");
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
use a different thread to perform this task. If you do this in the main UI thread then it will freeze.. For example you can do following
new Thread() {
#Override
public void run() {
try {
Thread.sleep(Integer.parseInt(delayField.getText()) * 1000);
System.out.println("Hello!");
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}.start();
UPDATE
AFter wise suggestions of Robin and Marko I am updating the answer with a better solution.
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println("Hello!");
}
};
javax.swing.Timer t = new javax.swing.Timer(Integer.parseInt(delayField.getText()) * 1000, taskPerformer);
t.setRepeats(false);
t.start();
Whenever you are about to use Thread.sleep in your GUI code, stop yourself and think of Swing Timer, which is the right tool for the job. Schedule the task you need to perform with a delay.
Using another thread for this is not the best advice: it wastes a heavy system resource (a thread) to do absolutely nothing but wait.
This is not the correct way to use threads in java . You should use swingutilities.invokelater
swing utils invoke later
You don't want to execute this on the UI (or event dispatch thread) thread. Rather in a separate thread. Otherwise (as you've seen) you'll block the UI.
It's a good practice to perform time-consuming operations on a separate thread, and make use of SwingUtilities.invokeLater() if those threads need to perform some subsequent UI action (e.g. in the above display "Hello" in the UI)
I'm making a simple game in Java using swing and am having problems with my GUI freezing up sporadically (due to threading issues most probably) after a button press that is supposed to trigger a switch in JPanels.
I posted a related thread here, which has more details about the actual code I'm currently using (although I did update the countdown and get that working fine). From answers to that thread, it seems like usingSwingUtilities.invokeLater() or invokeAndWait() might be what I need to solve the problem, but I'm not sure where in my code it is necessary or exactly how to implement it.
I don't know that much about threading and could use any help (preferably somewhat detailed and with some sample code) that I can get. Let me know if any further details would be useful.
See: Tutorial: Concurrency in Swing
Generally speaking, the Event Dispatch Thread is a single thread, chugging through the event queue, processing one at a time.
SwingUtilities.invokeLater(..)
puts a Runnable on this queue. So it will be processed by the EDT when the EDT finishes everything on the queue before it (This is why sleeping on the queue blocks other events like repainting). It's relatively unusual to call invokeLater(..) from the EDT itself, though there are situations where it is useful (usually as a hack). I don't think I have had a legitimate use for SwingUtilities.invokeAndWait(..) in the last 6 years. Maybe once.
javax.swing.Timer can be configured to fire once or periodically. When it fires, it puts an event on the EDT queue. If you have computationally-intensive processing that need to be done, consider using javax.swing.SwingWorker to do the computation on another thread, and give you back the result in a thread-safe manner (this is also comparatively rare).
A good point to look is the docs. In your case, this explains how SwingUtilities.invokeLater() works and where to use it:
Causes doRun.run() to be executed asynchronously on the AWT event
dispatching thread. This method should be used when an application
thread needs to update the GUI.
So, in your actions that modifies the GUI you must use the invokeLater method to assure that the GUI wont freeze.
Another good resource is the Java tutorials. They cover concurrency in Swing.
I have create a WorkerThread class which take care of Threads and GUI current/main thread . i have put my GUI application in construct() method of WorkerThread when an event fire to start XXXServer then all threads are activate and GUI work smoothlly wihout freeze. have a look.
/**
* Action Event
*
* #see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent ae) {
log.info("actionPerformed begin..." + ae.getActionCommand());
try {
if (ae.getActionCommand().equals(btnStart.getText())) {
final int portNumber = 9990;
try {
WorkerThread workerThread = new WorkerThread(){
public Object construct(){
log.info("Initializing the XXXServer ...");
// initializing the Socket Server
try {
XXXServer xxxServer = new XXXServer(portNumber);
xxxServer.start();
btnStart.setEnabled(false);
} catch (IOException e) {
// TODO Auto-generated catch block
log.info("actionPerformed() Start button ERROR IOEXCEPTION..." + e.getMessage());
e.printStackTrace();
}
return null;
}
};workerThread.start();
} catch (Exception e) {
log.info("actionPerformed() Start button ERROR..." + e.getMessage());
e.printStackTrace();
}
} else if (ae.getActionCommand().equals(btnStop.getText())) {
log.info("Exit..." + btnStop.getText());
closeWindow();
}
} catch (Exception e) {
log
.info("Error in ServerGUI actionPerformed==="
+ e.getMessage());
}
}
In order to invoke an action in the existing WorkerThread, one would intuitively send a user defined event using SwingUtilities.invokeLater() to a JFrame's actionPerformed() method as
class TestFrame extends JFrame implements ActionListener
{
...
private class Performer implements Runnable
{
ActionEvent event;
Performer(ActionEvent event)
{
this.event = event;
}
#Override
public void run()
{
actionPerformed(event);
}
}
synchronized protected void invokeLater(ActionEvent event)
{
SwingUtilities.invokeLater(new Performer(event));
}
public void actionPerformed(ActionEvent event)
{
...
}
}
Now, TestFrame.invokeLater() called in any Thread will be processed in TestFrame.actionPerformed() in existing WorkerThread .
So my program has multiple classes and after one of them has run, it'd like it so it appends the text area in the main class GUI with a 'finished' message
ta.append("Search Complete\n");
and this is the code that needs to complete
statCl.addActionListener(new ActionListener(){
public void actionPerformed (ActionEvent e) {
try {
ta.append("Searching...\n");
task.execute();
} catch (Exception IOE) {}
}
});
So it is in the class where task where actual code runs.
Any advice or help would be amazing, thanks.
If the task.execute() method doesn't start launch an operation in another thread, then the GUI will be freezed, and nothing will apear in the text area until the operation is finished. So you might just have
ta.append("Searching...\n");
task.execute();
ta.append("Finished");
If the operation is launched in a new thread, then this thread should append in the text area, but it should make sure this append is done in the event dispatch thread (EDT). Your code could thus look like this :
public class Task {
private JTextArea ta;
public Task(JTextArea ta) {
this.ta = ta;
}
public void execute() {
Thread t = new Thread(new Runnable() {
// perform the long operation
// at the end, update the text area, in the EDT
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ta.append("finished");
}
});
}
t.start();
}
}
You might also look at SwingWorker, which is designed just for that (and other things like progress update). There is a code example in its class javadoc which does just what you're trying to do.
You should not be performing long-running task on EDT (event dispatching thread):
http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
Swing does all it's work on EDT, so you should not block EDT, e.g. run intensive tasks on it. Note: all event handlers are executed on EDT.
So there are two challenges:
Run intensive tasks in a background thread.
Update GUI, which must be done on EDT.
Use SwingWorker to solve this two issues.