Can multiple showMessageDialogs break swing? - java

This is simplified code, which would be called from pressing a button in my main JFrame class. Using this code, and then dismissing one of the resulting dialogs, causes all of my active windows in my Java session to either lock up or just go away.
//Broken code
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
List<JFrame> frameList = new ArrayList<>();
frameList.add(new TestJFrame());
frameList.add(new TestJFrame());
frameList.forEach(frame -> frame.setVisible(true));
frameList.forEach(frame -> {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(frame, "Msg", "Title", 0);
frame.setVisible(false);
frame.dispose();
});
});
}
However, if I were to remove the SwingUtilities.invokeLater() section then it works like I would expect (dialog pops up, close the dialog, window goes away, repeat).
//Working code
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
List<JFrame> frameList = new ArrayList<>();
frameList.add(new TestJFrame());
frameList.add(new TestJFrame());
frameList.forEach(frame -> frame.setVisible(true));
frameList.forEach(frame -> {
//SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(frame, "Msg", "Title", 0);
frame.setVisible(false);
frame.dispose();
//});
});
}
I'd rather not use the second one because the actual code is being started in a background thread that is notifying a set of listeners, so if I were to use the second one then it would block up the thread and slow down listeners until the user responds (when I could be processing during that time). What about the invokeLater() is breaking me? Is this expected behavior?
NOTE: This is simplified code pulled out of how I'm actually using it, but the core issue still exists (I have multiple JFrames, and if multiple JOptionPane.showMessageDialog()s were put on invokeLater()s for different JFrames then it breaks me. I tested the above code with a new, isolated, JFrame class created in Netbeans and was able to reproduce the error.
EDIT: I can't seem to reproduce the error in Windows, only seems to happen in Linux.

It is most likely invokeLater() which is breaking your code. If you want to thread this action try using a simple thread or
EventQueue.invokeLater(new Runnable()
{
public void run()
{ //Your joptionpane here
}
});`

Instead of invoke later i prefer using a
1) simple thread
2) TimerTask
3) ScheduledExecutorService
Use one of these methods.
This is an example for using timer task
import java.util.Timer;
import java.util.TimerTask;
public class Task2 {
public static void main(String[] args) {
TimerTask task = new TimerTask() {
#Override
public void run() {
// task to run goes here
System.out.println("Hello !!!");
}
};
Timer timer = new Timer();
long delay = 0;
long intevalPeriod = 1 * 1000;
// schedules the task to be run in an interval
timer.scheduleAtFixedRate(task, delay,
intevalPeriod);
} // end of main
}
If you are not satisfied you can use invoke later.
But remember never use invoke and wait its a bad idea

Here is my approach, as I understand the problem is on the locked windows, which are waiting for an event to finish, in swing the events are related with the AWT-EventQueue.
Here is a little explanation about: https://stackoverflow.com/a/22534931/1670134
So, in order to get your window working I used the Future type:
From the java doc:
A Future represents the result of an asynchronous computation. Methods
are provided to check if the computation is complete, to wait for its
completion, and to retrieve the result of the computation. The result
can only be retrieved using method get when the computation has
completed, blocking if necessary until it is ready.
package com.stackoverflow.future;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import com.stackoverflow.frame.MyFrame;
public class MySwingWorker extends SwingWorker<Void, Void>{
#Override
protected Void doInBackground() throws Exception {
final ExecutorService service = Executors.newFixedThreadPool(1);
List<Future<JFrame>> frameList = new ArrayList<Future<JFrame>>();
frameList.add(service.submit(new SwingLoader(new MyFrame())));
frameList.add(service.submit(new SwingLoader(new MyFrame())));
try {
service.shutdown();
service.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
service.shutdownNow();
}
return null;
}
public static void main(String[] args) {
MySwingWorker mySwingWorker = new MySwingWorker();
SwingUtilities.invokeLater(mySwingWorker);
}
}
The loader:
package com.stackoverflow.future;
import java.util.concurrent.Callable;
import javax.swing.JFrame;
public class SwingLoader implements Callable<JFrame>{
private JFrame frame;
public SwingLoader(JFrame frame){
this.frame = frame;
}
#Override
public JFrame call() throws Exception {
frame.setVisible(true);
return frame;
}
}
NOTE: This code is just a proto, in order to provide you with ideas and it must be modified and cleaned in order to achieve the desired results.
Here you are a link with a couple of explanations of each type:
http://winterbe.com/posts/2015/04/07/java8-concurrency-tutorial-thread-executor-examples/

Related

Using Platform.exit() and System.exit(int) together

I would like to close a javafx application with a specified return code. Browsing through answers on SO, I found the following idiom:
Platform.exit();
System.exit(0);
for example here:
Stop threads before close my JavaFX program
or here: JavaFX application still running after close
These two methods executed one after another look like we are attempting to duplicate some actions. I would assume, that if Platform.exit() is successful, it should not return to the place where System.exit(0) is called. If however Platform.exit() only triggers some closing action running on another thread, returns and System.exit(0) can be called then this may cause some race condition, where two threads are trying to close the same application.
So, how does this idiom exactly work?
Calling System.exit(...) terminates the Java Virtual Machine.
As I understand it, calling Platform.exit() just signals the JavaFX Toolkit to shut down, resulting in the application instance's stop() method being called on the FX Application thread, and the FX Application Thread being allowed to terminate. This in turn causes Application.launch() to return. If you are using the usual idiom in your main(...) method:
public static void main(String[] args) {
Application.launch(args);
}
then once launch() returns, there is nothing left for the main() method to do, and no (as long as no non-daemon threads are running) the application exits in a normal way. Platform.exit() does not create a call to System.exit(...) under any circumstances: however under certain circumstances it will allow the JVM to exit simply because there is nothing left for it to do.
If you call System.exit(...) the JVM basically exits immediately. So, for example, if you have code in the main(...) method after Application.launch(), that code gets executed after a call to Platform.exit(), but not after a call to System.exit(...). Similarly, if you override Application.stop(), the stop() method is called after a call to Platform.exit(), but not after a call to System.exit(...).
If you have non-daemon threads running, Platform.exit() will not forcibly shut them down, but System.exit() will.
The following example should demonstrate this:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class ExitTest extends Application {
#Override
public void stop() {
System.out.println("Stop called");
}
#Override
public void start(Stage primaryStage) {
Button startThread = new Button("Start non-daemon thread");
startThread.setOnAction(e -> new Thread(() -> {
System.out.println("Starting thread");
try {
Object lock = new Object();
synchronized(lock) {
lock.wait();
}
} catch (InterruptedException exc) {
System.err.println("Interrupted");
Thread.currentThread().interrupt();
} finally {
System.out.println("Thread complete");
}
}).start());
Button exit = new Button("Simple Exit");
exit.setOnAction(e -> {
System.out.println("Calling Platform.exit()");
Platform.exit();
});
Button forceExit = new Button("Force exit");
forceExit.setOnAction(e -> {
System.out.println("Calling Platform.exit():");
Platform.exit();
System.out.println("Calling System.exit(0):");
System.exit(0);
});
Scene scene = new Scene(new HBox(5, startThread, exit, forceExit));
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
System.out.println("launch() complete");
}
}
It's generally recommended that you exit a JavaFX Application with a call to Platform.exit(), which allows for a graceful shutdown: for example if there is any "cleanup" code you need, you can put it in the stop() method and Platform.exit() will allow it to be executed. If you are running background threads which must be terminated, either make them daemon threads, or execute them via an executor service, and shut down the executor service from the stop() method. Here is a modification to the above example which uses this technique.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class ExitTest extends Application {
private final ExecutorService exec = Executors.newCachedThreadPool();
#Override
public void stop() throws InterruptedException {
System.out.println("Stop called: try to let background threads complete...");
exec.shutdown();
if (exec.awaitTermination(2, TimeUnit.SECONDS)) {
System.out.println("Background threads exited");
} else {
System.out.println("Background threads did not exit, trying to force termination (via interruption)");
exec.shutdownNow();
}
}
#Override
public void start(Stage primaryStage) {
Button startThread = new Button("Start non-daemon thread");
startThread.setOnAction(e -> {
exec.submit( () -> {
System.out.println("Starting thread");
try {
// just block indefinitely:
Object lock = new Object();
synchronized(lock) {
lock.wait();
}
} catch (InterruptedException exc) {
System.out.println("Interrupted");
Thread.currentThread().interrupt();
} finally {
System.out.println("Thread complete");
}
});
});
Button exit = new Button("Simple Exit");
exit.setOnAction(e -> {
System.out.println("Calling Platform.exit()");
Platform.exit();
});
Scene scene = new Scene(new HBox(5, startThread, exit));
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
System.out.println("launch() complete");
}
}
If you want to use Platform.exit() in order to have a graceful shutdown, and you want to return a value from System.exit(...), the following approach should work. Note that this is not really a recommended practice anyway: in production code you should not really rely on the platform supporting a process exit code at all.
public class App extends Application {
private static int exitCode = 0 ;
public static exit(int exitCode) {
App.exitCode = exitCode ;
Platform.exit();
}
#Override
public void start(Stage primaryStage) {
// ...
someThing.addEventHander(someEventType, e -> App.exit(42));
// ...
}
#Override
public void stop() {
// cleanup code...
}
public static void main(String[] args) {
Application.launch(args);
System.exit(exitCode);
}
}
well the Doc is your friend in such a case:
calling System.exit(0) will terminate the JVM
Terminates the currently running Java Virtual Machine. The argument
serves as a status code; by convention, a nonzero status code
indicates abnormal termination. This method calls the exit method in
class Runtime. This method never returns normally.
and doing Platform.exit() will terminates the FX application
Causes the JavaFX application to terminate. If this method is called
after the Application start method is called, then the JavaFX launcher
will call the Application stop method and terminate the JavaFX
application thread. The launcher thread will then shutdown. If there
are no other non-daemon threads that are running, the Java VM will
exit. If this method is called from the Preloader or the Application
init method, then the Application stop method may not be called.
Another approach, that avoids hacks, would be to check if any stages are open and close them using Stage.close(), and then call Platform.exit(). For example, in a two window app:
if (secondWindow != null) secondWindow.close();
Platform.exit();

actionListener interfaces actionPerformed method not working with Timer class

the following program is suppose to print the date after every second. however this is not working for an known reason.
i have implemented the ActionListener interface in the following class and the actionPerformed method:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
public class CurrentTimePrinter implements ActionListener{
public void actionPerformed(ActionEvent e){
System.out.println(new Date());
}
}
this is the tester class:
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class CurrentTimePrinterTester {
public static void main(String[] args) {
ActionListener listener = new CurrentTimePrinter();
Timer t = new Timer(1000, listener);
t.start();
}
}
You need to execute your code on a non-daemon thread. What currently happens is that the Timer starts as a daemon thread, but as main returns the the JVM exits.
You can start the timer from the EDT (which is non-daemon) like this:
public static void main(String[] args) {
ActionListener listener = new CurrentTimePrinter();
SwingUtilities.invokeLater(() -> new Timer(1000, listener).start());
}
and this keeps the JVM alive.
A few extra notes on threading:
The swing.Timer is a simplified class that was customized for use with GUIs. With this comes the disadvantage of less flexibility. The thread on which all such timers run is set in the background and is daemon.
The util.Timer has by default a non-daemon thread and has the flexibility to be created otherwise. Each timer has its own thread.

Java swing sound playback ends prematurely

Within a Java swing application, the following snippet is supposed to play a siren. It starts OK but stops prematurely, not always at the same time (i.e. sometimes it stops almost immediately and sometimes after a longer delay, but usually it does not finish playing the whole sound file). What could be causing this?
I've done my best to create a minimal example that still has the problem:
package monster;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.io.File;
import javafx.embed.swing.JFXPanel;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example_2 extends JPanel {
protected static final long serialVersionUID = 1L;
public Example_2() {
setPreferredSize(new Dimension(100,100));
setBackground(Color.white);
createPanel();
}
public static void main(String[] args) {
Example_2 e = new Example_2();
JFrame f = new JFrame();
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
f.add(e, BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
new Thread(
new Runnable() {
public void run() {
try {
File f = new File("sound/siren_short.wav");
String url = "file:///"+f.getAbsolutePath().replaceAll("\\\\","/").replaceAll(" ", "%20");
MediaPlayer mp = new MediaPlayer(new Media(url));
mp.play();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
public static JFXPanel createPanel() {
return new JFXPanel();
}
}
In the current example code "Example2" posted, it looks to me like the main() executes and exits. Yes, the call to MediaPlayer launches a background thread, but I'm guessing when the main() ends, this terminates the MediaPlayer thread as well (perhaps because it only has daemon status). I haven't used the MediaPlayer yet, myself, so I don't know if this behavior can result or not.
Here is a simple test for you: add the following line.
Thread.sleep(5000); // pauses 5 seconds
or something similar to the end of the main(), after the repaint() call. The number is milliseconds: use a number that is longer than the length of your sound. Does the sound now play to completion? You'll probably have to put the new line of code in a try...catch block.
Check out the api for Thread() when you get a chance. When you get to the page, I'd recommend doing a search on "daemon". There are methods for testing or setting daemon status, plus a terse explanation of what the status means. There is a chance that if you set your runnable to not be a daemon, the program (as shown) will play once and then hang with no way to terminate it except killing it via Eclipse (if it was run in Eclipse) or via an OS task manager.
I haven't delved much into debugging threads in Eclipse--am afraid I can't offer any suggestions there.
Andrew Thompson made a good suggestion, to make use of Clip. This has the benefit of keeping us in "familiar" territory. I've used Clip frequently, but not JavaFX libraries. If you had used Clip, the line of code I'm suggesting (Thread.sleep) would definitely have been needed to allow the sound to play to completion.
Here is a theory: the code which loads and executes the play() command is non-daemon. However, the background processes which deliver the sound data to the line are daemon. If that were the case, then the behavior I describe (termination after the main thread is done) would be consistent.

creat flashing text by using java multithread method sleep()

hi im creating a flashing text frame by using threading handling method, here is my code:
import javax.swing.*;
public class FlashingText extends JApplet implements Runnable {
/**
*
*/
private static final long serialVersionUID = 1L;
private JLabel jlblText = new JLabel("welcome",JLabel.CENTER);
public FlashingText() {
add(jlblText);
new Thread(this).start();
}
#Override
public void run() {
try {
while(true) {
if(jlblText.getText() == null) {
jlblText.setText("Welcome");
Thread.sleep(2000);
} else
jlblText.setText(null);
}
} catch(InterruptedException ex) {
}
}
}
after i compiled and ran it, it seems the text does not flashing at all
is there anything wrong with my code?
thanks a lot!
There's a better solution, which updates the UI in Event Dispatcher Thread and does not block it.
final JLabel label = new JLabel("Some text");
final Runnable updater = new Runnable() {
#Override
public void run() {
label.setVisible(!label.isVisible());
}
};
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
executorService.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
SwingUtilities.invokeLater(updater);
}
}, 2, 2, TimeUnit.SECONDS);
From the code, it does not really seem that you are flashing anything. Some issues I see with your code:
If the label has no text, the getText() method will yield an empty string ("") and not null.
When updating visual components, you would need to go through the Event Dispatcher Thread (EDT). This is exposed to you through the SwingUtilities.invokeLater(Runnable runnable) class.
It is usually a bad idea to sleep() threads. If you make the changes through the EDT, you would be hanging the ED Thread which will cause the application UI to freeze, which is not desired.
You are swallowing exceptions. In your exception handling, you are not doing anything. It is considered bad practice to not handle exceptions (sometimes a simple log message will do).
According to me there is a problem in the following code block:
try {
while(true) {
if(jlblText.getText() == null) {
jlblText.setText("Welcome");
Thread.sleep(2000);
} else
jlblText.setText(null);
}
}
Because see at the first time the value is welcome, so it will enter the loop and go to else and set it null and then immediately it will check again, as there is no sleep in else so it will check again and enter the if block and set it to welcome, and this whole process will be done at a great speed so you would not be able to see the flashing effect. So I think that you should try putting a sleep at the end of the else block and see, according to me it should work then.
You should change:
else
jlblText.setText(null);
to
else{
jlblText.setText(null);
Thread.sleep(500);
}
or something like this

Suspend test execution until application becomes idle

Is it feasible to implement some util method to suspend test (current thread) execution until application becomes idle?
Idle means:
1. there were no GUI events added to event queue for some period of time
2. there were no worker threads running any tasks for the same period of time.
Could you please provide implementation/code snippets to track previous conditions of idleness?
You can replace the EventQueue with your own implementation, as shown here. The variation below adds an idle() method that relies on an arbitrary THRESHOLD of 1000 ms.
import java.awt.AWTEvent;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JTree;
/**
* #see https://stackoverflow.com/questions/7976967
* #see https://stackoverflow.com/questions/3158254
*/
public class EventQueueTest {
public static void main(String[] args) throws
InterruptedException, InvocationTargetException {
EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
final MyEventQueue q = new MyEventQueue();
eventQueue.push(q);
EventQueue.invokeAndWait(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JTree());
f.pack();
f.setVisible(true);
}
});
// Test idle() on initial thread
for (int i = 0; i < 10; i++) {
Thread.sleep(2 * MyEventQueue.THRESHOLD);
System.out.println("Idle: " + q.idle());
}
}
private static class MyEventQueue extends EventQueue {
private static final int THRESHOLD = 1 * 1000;
private long last;
#Override
public void postEvent(AWTEvent e) {
super.postEvent(e);
last = System.currentTimeMillis();
}
public boolean idle() {
return System.currentTimeMillis() - last > THRESHOLD;
}
}
}
You can use Toolkit.getDefaultToolkit().addAWTEventListener(listener, eventMask) to subscribe to AWT event queue, so you can detect whether events are not added for some period of time.
I think that you need your custom code to monitor working threads, i.e. something in the beginning and end of run() method.
The problem is to "suspend the test execution". If your test is running in thread theoretically you can invoke the thread's suspend() method. But it is deprecated and should not be used. To perform clear implementation you should make your custom code that asks status during execution of the thread and calls wait() once it detects that the test must be suspended. When your code that monitors AWT event queue and working threads decides that test may be resumed it should call appropriate notify().
Probably better solution from design point of view is Actors model. There are several java framework that provide this functionality.

Categories