I just encountered a problem when trying to add an imprint to a swing application which is shown for five seconds when the application is closed.
I had planned to open a JDialog just containing a simple image when the main frame is closed.
I got a function showing the JDialog (I removed everything which is not necessary).
public static void show() {
JDialog d = new JDialog();
JLabel l = new JLabel(new ImageIcon(MainController.class.getClass().getResource("/path/to/endlogo.png")));
d.add(l);
d.setVisible(true);
}
The function is called by the following snippet (in the window listener of my main window)
#Override
public void windowClosing(WindowEvent e) {
show();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The problem is that the dialog is shown AFTER the five seconds (which is when the windows is already closed and the application exited, I tested it and it showed up perfectly after five seconds when run on application start).
Do you guys know a way to achieve it the other way round?
You're blocking the UI thread. Don't do that, basically... use a swing timer or something similar if you want to do something on the UI thread at a later time.
Golden rules:
Don't do anything time consuming on the UI thread
Only access the UI on the UI thread
Related
Related to my previous question: Call repaint from another class in Java?
I'm new to Java and I've had a look at some tutorials on SwingWorker. Yet, I'm unsure how to implement it with the example code I gave in the previous question.
Can anyone please explain how to use SwingWorker with regards to my code snippet and/or point me towards a decent tutorial? I have looked but I'm not sure I understand yet.
Generally, SwingWorker is used to perform long-running tasks in Swing.
Running long-running tasks on the Event Dispatch Thread (EDT) can cause the GUI to lock up, so one of the things which were done is to use SwingUtilities.invokeLater and invokeAndWait which keeps the GUI responsive by which prioritizing the other AWT events before running the desired task (in the form of a Runnable).
However, the problem with SwingUtilities is that it didn't allow returning data from the the executed Runnable to the original method. This is what SwingWorker was designed to address.
The Java Tutorial has a section on SwingWorker.
Here's an example where a SwingWorker is used to execute a time-consuming task on a separate thread, and displays a message box a second later with the answer.
First off, a class extending SwingWorker will be made:
class AnswerWorker extends SwingWorker<Integer, Integer>
{
protected Integer doInBackground() throws Exception
{
// Do a time-consuming task.
Thread.sleep(1000);
return 42;
}
protected void done()
{
try
{
JOptionPane.showMessageDialog(f, get());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
The return type of the doInBackground and get methods are specified as the first type of the SwingWorker, and the second type is the type used to return for the publish and process methods, which are not used in this example.
Then, in order to invoke the SwingWorker, the execute method is called. In this example, we'll hook an ActionListener to a JButton to execute the AnswerWorker:
JButton b = new JButton("Answer!");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
new AnswerWorker().execute();
}
});
The above button can be added to a JFrame, and clicked on to get a message box a second later. The following can be used to initialize the GUI for a Swing application:
private void makeGUI()
{
final JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new FlowLayout());
// include: "class AnswerWorker" code here.
// include: "JButton" b code here.
f.getContentPane().add(b);
f.getContentPane().add(new JButton("Nothing"));
f.pack();
f.setVisible(true);
}
Once the application is run, there will be two buttons. One labeled "Answer!" and another "Nothing". When one clicks on the "Answer!" button, nothing will happen at first, but clicking on the "Nothing" button will work and demonstrate that the GUI is responsive.
And, one second later, the result of the AnswerWorker will appear in the message box.
Agree:
Running long-running tasks on the Event Dispatch Thread (EDT) can cause the GUI to lock up.
Do not agree:
so one of the things which were done is to use SwingUtilities.invokeLater and invokeAndWait which keeps the GUI responsive..
invokeLater still runs the code on the EDT, and can freeze your UI!! Try this:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
At least I, cannot move my mouse once I click the button which triggers the actionPerformed with the above code. Am I missing something?
I'm writing an application that adds cards (JPanels) to a CardLayout during runtime. The problem is that some components on the card loads faster than others, making it appear glitchy and not properly rendered before it's displayed.
I want it to be ready when shown for the first time.
I have solved the issue temporary by a loading screen, which makes the thread sleep for 1500 ms. Is there a more exakt way to know if everything on the panel is loaded?
private void showLoadingScreen() {
final Component glassPane = getGlassPane();
setGlassPane(loadingPanel);
loadingPanel.setVisible(true);
Thread thread = new Thread() {
public void run() {
try {;
Thread.sleep(1500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setGlassPane(glassPane);
}
};
thread.start();
}
Do all your file loading and data manipulation in a background thread that is created using a SwingWorker. Then before executing the SwingWorker, add a PropertyChangeListener. When the PropertyChangeEvents newValue is SwingWorker.StateValue.DONE, then you know all background work is done and you can display your GUI.
Please have a look at the Concurrency in Swing tutorial, and for an example, please have a look at this answer to a similar question.
I was building a small test tool with Java Swing using Netbeans IDE.
I am trying to update a label, which is somehow not getting 'repainted'/'refreshed'. I looked into a couple of similar questions on SO but was not able to resolve my problem.
private void excelFileChooserActionPerformed(java.awt.event.ActionEvent evt)
{
if(!JFileChooser.CANCEL_SELECTION.equals(evt.getActionCommand()))
{
String selectedFile = excelFileChooser.getSelectedFile().getAbsolutePath();
loaderLabel.setText("Please Wait..");
try {
//This is sort of a blocking call, i.e. DB calls will be made (in the same thread. It takes about 2-3 seconds)
processFile(selectedFile);
loaderLabel.setText("Done..");
missingTransactionsPanel.setVisible(true);
}
catch(Exception e) {
System.out.println(e.getMessage());
loaderLabel.setText("Failed..");
}
}
}
loaderLabel is a JLabel and the layout used is AbsoluteLayout.
So, my problem is "Please Wait..." is never shown. Although call to the method processFile takes about 2-3 seconds, "Please Wait..." is never shown. However, "Done..."/"Failed..." are shown.
If I add a popup (JOptionPane) before the call to processFile, "Please Wait.." is shown. I am not able to clearly understand why this is happening.
Is there a "good practice" that I should follow before a heavy method call? Do I need to call an explicit repaint/refresh/revalidate?
You need to call
processFile(selectedFile);
in another thread (not in the AWT thread). To do so you can do something like this :
Thread t = new Thread(){
public void run(){
processFile(selectedFile);
// now you need to refresh the UI... it must be done in the UI thread
// to do so use "SwingUtilities.invokeLater"
SwingUtilities.invokeLater(new Runnable(){
public void run(){
loaderLabel.setText("Done..");
missingTransactionsPanel.setVisible(true);
}
}
)
}
};
t.start();
Please not that I didn't work with swing for a long time, so there may be some syntax issues with this code.
Have you tried dispatching the call to the EDT with SwingUtilities.invokeLater() ?
http://www.javamex.com/tutorials/threads/invokelater.shtml
Can anyone tell me why does this timer run only once?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimerTest implements ActionListener{
private Robot r;
private Timer t;
private int i;
public TimerTest(){
i = 0;
try {
r = new Robot();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t = new Timer(1000, this);
t.setRepeats(true);
t.start();
}
public static void main(String [] args){
new TimerTest();
}
#Override
public void actionPerformed(ActionEvent arg0) {
i++;
System.out.println("Action..." + i);
}
The funny thing is that, if I decrease the delay in the Timer to just 100, it works as expected. And what's even funnier is that if I delete the code in which I initialize the Robot, it doesn't work at all, the program terminates as soon as I run it.
I've tried this on Windows 7 and on Ubuntu (although on Ubuntu I couldn't use the Robot at all, since I get an exception. Something related to rights, maybe).
Your main is processed so the program stops. You can test it by using this code, adding it to TimerTest()
JFrame testFrame = new JFrame();
testFrame.setVisible(true);
testFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
That JFrame keeps your main not from finshing, when you close the Frame the TimerTest ends. Which concludes your main which causes the main to finsh. Ending the program and stoping your swing timer.
See "main exits before javax.swing.Timer's start() can start" at the bug database.
Evaluation
Described behavior - when application exits before Swing timer is started - is correct. Here is what's going then:
Swing timer is created.
Separate thread for swing timer is started. It will notify attached actionListeners when the timeout is passed by posting an instance of InvocationEvent to EDT.
Main thread exits.
At this moment there is no non-daemon threads running in JVM. Application is terminated.
..the evaluator goes on to add..
..This looks like a RFE rather than a defect.
One surefire way to make it behave is to create a GUI element and display it. Which is why I asked earlier..
..why exactly are you creating the timer without any GUI elements? Is this for repeated screen-shots?
To handle that situation, I would typically create and show a frame to allow the user to configure the rate and area for screenshots, then minimize the frame and begin processing when the user clicks:
Screen Capture!
Related to my previous question: Call repaint from another class in Java?
I'm new to Java and I've had a look at some tutorials on SwingWorker. Yet, I'm unsure how to implement it with the example code I gave in the previous question.
Can anyone please explain how to use SwingWorker with regards to my code snippet and/or point me towards a decent tutorial? I have looked but I'm not sure I understand yet.
Generally, SwingWorker is used to perform long-running tasks in Swing.
Running long-running tasks on the Event Dispatch Thread (EDT) can cause the GUI to lock up, so one of the things which were done is to use SwingUtilities.invokeLater and invokeAndWait which keeps the GUI responsive by which prioritizing the other AWT events before running the desired task (in the form of a Runnable).
However, the problem with SwingUtilities is that it didn't allow returning data from the the executed Runnable to the original method. This is what SwingWorker was designed to address.
The Java Tutorial has a section on SwingWorker.
Here's an example where a SwingWorker is used to execute a time-consuming task on a separate thread, and displays a message box a second later with the answer.
First off, a class extending SwingWorker will be made:
class AnswerWorker extends SwingWorker<Integer, Integer>
{
protected Integer doInBackground() throws Exception
{
// Do a time-consuming task.
Thread.sleep(1000);
return 42;
}
protected void done()
{
try
{
JOptionPane.showMessageDialog(f, get());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
The return type of the doInBackground and get methods are specified as the first type of the SwingWorker, and the second type is the type used to return for the publish and process methods, which are not used in this example.
Then, in order to invoke the SwingWorker, the execute method is called. In this example, we'll hook an ActionListener to a JButton to execute the AnswerWorker:
JButton b = new JButton("Answer!");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
new AnswerWorker().execute();
}
});
The above button can be added to a JFrame, and clicked on to get a message box a second later. The following can be used to initialize the GUI for a Swing application:
private void makeGUI()
{
final JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new FlowLayout());
// include: "class AnswerWorker" code here.
// include: "JButton" b code here.
f.getContentPane().add(b);
f.getContentPane().add(new JButton("Nothing"));
f.pack();
f.setVisible(true);
}
Once the application is run, there will be two buttons. One labeled "Answer!" and another "Nothing". When one clicks on the "Answer!" button, nothing will happen at first, but clicking on the "Nothing" button will work and demonstrate that the GUI is responsive.
And, one second later, the result of the AnswerWorker will appear in the message box.
Agree:
Running long-running tasks on the Event Dispatch Thread (EDT) can cause the GUI to lock up.
Do not agree:
so one of the things which were done is to use SwingUtilities.invokeLater and invokeAndWait which keeps the GUI responsive..
invokeLater still runs the code on the EDT, and can freeze your UI!! Try this:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
At least I, cannot move my mouse once I click the button which triggers the actionPerformed with the above code. Am I missing something?