Why won't this shutdownhook work? - java

This is my main method and it contains a shutdownhook:
public static void main(String args[]) {
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
JOptionPane.showMessageDialog(null, "Shutdown hook");
}
});
/* Create and display the form */
java.awt.EventQueue.invokeLater(
new Runnable() {
#Override
public void run() {
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
MyFrame frame = new MyFrame();
frame.setVisible(true);
}
});
}
The problem is the JOptionPane doesn't show up at all. Instead, the frame closes but the app itself still runs.
PS. I can't use the WindowClosing event because it doesn't fire on the Cmd+Q command on Mac OS X.

The dispatch thread is already shut down, or is likely to be shut down before your submission to the queue is executed.
You need to find another way of trapping the quit events, shutdown hook is there so you can tidy up when the VM is exiting, so you really don't want to by tying up more resources in the UI when it is called.

Related

JFrame freezing when I call a class using JButton

Im not really an expert in programming and Im just starting to learn. Here is my problem.
I tried to call this class to start the server using a JButton but after the button was pressed the application freezes.
Here is my mouseClicked event
private void startbtnActionPerformed(java.awt.event.ActionEvent evt) {
new DisplayServer(80);
}
I suppose you block the Event Dispatcher Thread. Try to run it in a new Thread.
private void startbtnActionPerformed(java.awt.event.ActionEvent evt) {
new Thread(new Runnable() {
public void run() {
new DisplayServer(80);
}
}).start();
}
For more info read the article about Concurrency in Swing

Java SWT UI Thread freeze even if run in new Thread

I have a problem with a long running task.
After my dialog is shown I want to scan a ftp directory. This task takes some time so I need to run this task no in the UI thread.
My idea was
#Override
protected void postDialogOpen() {
// if invoked via menu button
if (!scanFtp) {
final Display display = Display.getDefault();
new Thread(new Runnable() {
#Override
public void run() {
//initProgressWaitViewer();
scanFtpServer();
//closeProgressWaitViewer();
display.syncExec(new Runnable() {
#Override
public void run() {
updateTree();
}
});
}
}).run();
}
}
But during the execution of scanFtpServer() my dialog is not movable and if I click on it it becomes "unresponsible".
Is there something I am doing wrong?
When calling method run() in class Thread, you are executing the method on the caller thread, just like calling any other method. If you want to spawn a new thread and execute method run() in that thread, you need to call method start() instead, that will do all the work of setting up the thread and running it.
So replace
}).run();
with
}).start();
Try to do .start() instead of .run() .

Trouble with SwingUtilities.invokeLater() updating GUI

I have been trying this all day in different variations with little success. Could someone please help explain what I am doing wrong? I am just a beginner with regards to threads.
private JTextArea text = new JTextArea();
private JButton button = new JButton("Cancel");
public StatusFrame() {
text.setEditable(false);
this.add(text);
this.add(button, BorderLayout.EAST);
this.setSize(new Dimension(150, 100));
this.setVisible(true);
}
public void updateStatus(String textIn) {
text.setText(textIn);
}
public JButton getButton() {
return button;
}
In another class, I am calling methods which may take a while to complete. I want to be able to call the StatusFrame.updateStatus() method to keep the user informed on the progress.
This is what I have:
someMethod() {
// prevent GUI from freezing using threads
final Runnable r = new Runnable() {
public void run() {
status = new StatusFrame();
}
};
SwingUtilities.invokeLater(r);
//do something
status.update("process 1 completed");
//do something else
status.updateStatus("Process 2 completed");
}
The frame appears but none of the code after the runnable appears to be run/processed. It just stops/blocks/something. But the GUI remains active
Thanks for any advice.
P.S.: I have tried using invokeAndWait() method but again not sure if I am doing it the right way. For now a quick fix would be preferred as I have not learned much about threads yet. Any instructions are welcome.
You have the concepts backwards.
Here's your code
someMethod() {
// prevent GUI from freezing using threads
final Runnable r = new Runnable() {
public void run() {
status = new StatusFrame();
}
};
SwingUtilities.invokeLater(r);
//do something
status.update("process 1 completed");
//do something else
status.updateStatus("Process 2 completed");
You should execute the long running code in a thread, and use the SwingUtilities invokeLater method to update the GUI.
someMethod() {
// prevent GUI from freezing using threads
final Runnable r = new Runnable() {
public void run() {
status = new StatusFrame();
}
};
new Thread(r).start();
// inside the StatusFrame
//do something
SwingUtilities.invokeLater(new Runnable() {
public void run() {
update("process 1 completed");
}
);
//do something else sometime later
SwingUtilities.invokeLater(new Runnable() {
public void run() {
update("Process 2 completed");
}
);
I don't know if I was clear in my answer.
Execute SwingUtilities.invokeLater when you start your Java application to make sure Swing components are on the Event Dispatch thread (EDT).
From the EDT, invoke long running processes as a runnable thread.
In the runnable thread, since you're not on the EDT, execute SwingUtilities.invokeLater whenever you're updating Swing components. This ensures that Swing components are updated on the EDT.
Every Swing application should start with a class like this:
import javax.swing.SwingUtilities;
import com.ggl.text.entry.model.TextEntryModel;
import com.ggl.text.entry.view.TextEntryFrame;
public class TextEntry implements Runnable {
#Override
public void run() {
new TextEntryFrame(new TextEntryModel());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new TextEntry());
}
}
This class does 3 things.
Constructs the GUI data model.
Constructs the GUI JFrame.
Ensures that the Swing components are on the EDT.
You'll need to call the updates on EDT too. I would suggest to sleep on the main thread, to give GUI a chance to show up before any other work:
someMethod() {
// prevent GUI from freezing using threads
Runnable r = new Runnable() {
public void run() {
status = new StatusFrame();
}
};
SwingUtilities.invokeLater(r);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
//do something
r = new Runnable() {
public void run() {
status.update("process 1 completed");
}
};
SwingUtilities.invokeLater(r);
//do something else
r = new Runnable() {
public void run() {
status.update("Process 2 completed");
}
};
SwingUtilities.invokeLater(r);
}
See Concurrency in Swing.
You may find using a Swing Worker easier to work with since it uses a Thread and has methods that will allow you to update the GUI properly.

How to interrupt threads with inline class in Java

I am implementing a program which rtp audio to a peer computer and in the same time running a threads to get ping data. Once I click the start button, two method start almost in the same time. The problem is when I want to interrupt/exit the program, the ping data will not show the output but the threads is still running.
Start button
JButton startCap = new JButton("Start");
startCap.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent act) {
go();//go() is the rtp audio method
Thread pinging = new Thread() {
public void run() {
PingTest();
}
};
pinging.setName("runPing");
pinging.start();
}
});
Exit button
JButton stopCap = new JButton("Exit");
stopCap.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent act) {
//just for some checking, I know its not a good design
//I new at here
if (sink != null) {
sink.addDataSinkListener(new DataSinkListener() {
public void dataSinkUpdate(DataSinkEvent e) {
if(e instanceof EndOfStreamEvent)
sink.close();
}
});
}
if (processor != null)
processor.stop();
System.exit(-1);
//I think there no need to return, but still put at there
Thread.currentThread().interrupt();//preserve the message
pinging.currentThread().interrupt();
return;//
//Runtime.getRuntime().halt(0);
//pinging.stop();
}
});
Some GUI code
public static void createAndShowGui() {
JFrame frame = new JFrame("Sender");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SimpleVoiceTransmiter());
frame.setSize(200, 75);
frame.setVisible(true);
frame.toFront();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
The go() is the main method while PingTest() is the dependent method, when go() start by clicking the "Start" button PingTest() will start. Now the problems is I don't know how to interupt/exit the PingTest(). How can I interrupt/exit all the threads (PingTest()) in the same time? Really need some hints, thanks in advanced.
p/s: PingTest() is using Runtime.exec() to ping the peer computer.
pinging.currentThread() doesn't return the pinging thread. It's equivalent to Thread.currentThread(), since currentThread() is a static method. To get the pinging thread, just use pinging:
pinging.interrupt();
I don't really understand why you would interrupt the current thread either. The current thread is the event dispatch thread, which is running your GUI. There is no reason to interrupt it.

How to close a Java Swing application from the code

What is the proper way to terminate a Swing application from the code, and what are the pitfalls?
I'd tried to close my application automatically after a timer fires. But just calling dispose() on the JFrame didn't do the trick - the window vanished but the application did not terminate. However when closing the window with the close button, the application does terminate. What should I do?
Your JFrame default close action can be set to "DISPOSE_ON_CLOSE" instead of EXIT_ON_CLOSE (why people keep using EXIT_ON_CLOSE is beyond me).
If you have any undisposed windows or non-daemon threads, your application will not terminate. This should be considered a error (and solving it with System.exit is a very bad idea).
The most common culprits are java.util.Timer and a custom Thread you've created. Both should be set to daemon or must be explicitly killed.
If you want to check for all active frames, you can use Frame.getFrames(). If all Windows/Frames are disposed of, then use a debugger to check for any non-daemon threads that are still running.
I guess a EXIT_ON_CLOSE
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
before System.exit(0) is better since you can write a Window Listener to make some cleaning operations before actually leaving the app.
That window listener allows you to defined:
public void windowClosing(WindowEvent e) {
displayMessage("WindowListener method called: windowClosing.");
//A pause so user can see the message before
//the window actually closes.
ActionListener task = new ActionListener() {
boolean alreadyDisposed = false;
public void actionPerformed(ActionEvent e) {
if (frame.isDisplayable()) {
alreadyDisposed = true;
frame.dispose();
}
}
};
Timer timer = new Timer(500, task); //fire every half second
timer.setInitialDelay(2000); //first delay 2 seconds
timer.setRepeats(false);
timer.start();
}
public void windowClosed(WindowEvent e) {
//This will only be seen on standard output.
displayMessage("WindowListener method called: windowClosed.");
}
Try:
System.exit(0);
Crude, but effective.
May be the safe way is something like:
private JButton btnExit;
...
btnExit = new JButton("Quit");
btnExit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
Container frame = btnExit.getParent();
do
frame = frame.getParent();
while (!(frame instanceof JFrame));
((JFrame) frame).dispose();
}
});
The following program includes code that will terminate a program lacking extraneous threads without explicitly calling System.exit(). In order to apply this example to applications using threads/listeners/timers/etc, one need only insert cleanup code requesting (and, if applicable, awaiting) their termination before the WindowEvent is manually initiated within actionPerformed().
For those who wish to copy/paste code capable of running exactly as shown, a slightly-ugly but otherwise irrelevant main method is included at the end.
public class CloseExample extends JFrame implements ActionListener {
private JButton turnOffButton;
private void addStuff() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
turnOffButton = new JButton("Exit");
turnOffButton.addActionListener(this);
this.add(turnOffButton);
}
public void actionPerformed(ActionEvent quitEvent) {
/* Iterate through and close all timers, threads, etc here */
this.processWindowEvent(
new WindowEvent(
this, WindowEvent.WINDOW_CLOSING));
}
public CloseExample() {
super("Close Me!");
addStuff();
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
CloseExample cTW = new CloseExample();
cTW.setSize(200, 100);
cTW.setLocation(300,300);
cTW.setVisible(true);
}
});
}
}
If I understand you correctly you want to close the application even if the user did not click on the close button. You will need to register WindowEvents maybe with addWindowListener() or enableEvents() whichever suits your needs better.
You can then invoke the event with a call to processWindowEvent(). Here is a sample code that will create a JFrame, wait 5 seconds and close the JFrame without user interaction.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ClosingFrame extends JFrame implements WindowListener{
public ClosingFrame(){
super("A Frame");
setSize(400, 400);
//in case the user closes the window
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
//enables Window Events on this Component
this.addWindowListener(this);
//start a timer
Thread t = new Timer();
t.start();
}
public void windowOpened(WindowEvent e){}
public void windowClosing(WindowEvent e){}
//the event that we are interested in
public void windowClosed(WindowEvent e){
System.exit(0);
}
public void windowIconified(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowActivated(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}
//a simple timer
class Timer extends Thread{
int time = 10;
public void run(){
while(time-- > 0){
System.out.println("Still Waiting:" + time);
try{
sleep(500);
}catch(InterruptedException e){}
}
System.out.println("About to close");
//close the frame
ClosingFrame.this.processWindowEvent(
new WindowEvent(
ClosingFrame.this, WindowEvent.WINDOW_CLOSED));
}
}
//instantiate the Frame
public static void main(String args[]){
new ClosingFrame();
}
}
As you can see, the processWindowEvent() method causes the WindowClosed event to be fired where you have an oportunity to do some clean up code if you require before closing the application.
Take a look at the Oracle Documentation.
Starting from JDK 1.4 an Application terminates if:
There are no displayable AWT or Swing components.
There are no native events in the native event queue.
There are no AWT events in java EventQueues.
Cornercases:
The document states that some packages create displayable components without releasing them.A program which calls Toolkit.getDefaultToolkit() won't terminate. is among others given as an example.
Also other Processes can keep AWT alive when they, for what ever reason, are sending events into the native event queue.
Also I noticed that on some Systems it takes a coupple of seconds before the Application actually terminates.
I think, the idea is here the WindowListener - you can add any code there that you'd like to run before the thing shuts down
In response to other comments, DISPOSE_ON_CLOSE does not seem to properly exit the application - it only destroys the window, but the application will continue running. If you want to terminate the application use EXIT_ON_CLOSE.

Categories