So in this chunk of code:
//Actions performed when an event occurs.
public void actionPerformed(ActionEvent event)
{
String command = event.getActionCommand();
//If btnConvertDocuments is clicked, the FileConverter method is called and the button is then disabled [so as to prevent duplicates].
if (command.equals("w"))
{
new Thread(new Runnable()
{
public void run()
{
FileConverter fc = new FileConverter();
}
}).start();
btnConvertDocuments.setEnabled(false);
//Validation message ensuring completion of the step.
JOptionPane.showMessageDialog(this, "Step 1 Complete!", "Validation", JOptionPane.INFORMATION_MESSAGE);
}
It seems like the message dialog window pop-ups way too fast, before the FileConverter method isn't even finished being called. I was wondering if the placement of JOptionPane was correct, or if there was a way to delay a message until the method finished processing?
You can use the SwingWorker.
Have a look here, java tutorial.
SwingWorker worker = new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() {
FileConverter fc = new FileConverter();
return null;
}
#Override
public void done() {
JOptionPane.showMessageDialog(this, "Step 1 Complete!", "Validation", JOptionPane.INFORMATION_MESSAGE);
}
};
You should use a Swing Timer with a delay, instead of using your own Thread and Runnable for this.
You can use Swing timers in two ways:
To perform a task once, after a delay.
For example, the tool tip manager uses Swing timers to determine when to show a tool tip and when to hide it.
To perform a task repeatedly.
For example, you might perform animation or update a component that displays progress toward a goal.
An example from the documentation:
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
}
};
Timer myTimer = new Timer(delay, taskPerformer);
myTimer.setRepeats(false);
myTimer.start();
Related
On clicking an image I want another image to be displayed pause for one second and the original image to be restored and displayed againdisplayed again When I try to do it it action handler such as code given below it sets the image after sleep .I want the image to be displayed pause and the original to be displayed again how can I achieve that
private void jButton16ActionPerformed(java.awt.event.ActionEvent evt) {
jButton16.setIcon(new javax.swing.ImageIcon("C:\\Users\\x\\Documents\\O.png"));
try { //sleep 1 seconds
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
jButton16.setIcon(new javax.swing.ImageIcon("C:\\Users\\x\\Documents\\118px-AMIGO.jpg")); }
Swing is single threaded, you should never perform long running or blocking operations within the context of the Event Dispatching Thread
Swing is NOT thread safe, this means you should never update the UI (and anything the UI needs) outside of the context of the EDT
The simplest solution to your problem is to use a Swing Timer
private void jButton16ActionPerformed(java.awt.event.ActionEvent evt) {
jButton16.setIcon(new javax.swing.ImageIcon("C:\\Users\\x\\Documents\\O.png"));
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jButton16.setIcon(new javax.swing.ImageIcon("C:\\Users\\x\\Documents\\118px-AMIGO.jpg"));
}
});
timer.setRepeats(false);
timer.start();
}
See Concurrency in Swing and How to use Swing Timers for more details
You should never invoke Thread.sleep() inside Event Dispatch Thread
because Thread.sleep() will block Event Dispatch Thread and your UI will be Freeze , instead you could use a Timer to achieve your goal
Refer below code,
jButton16.setIcon(new javax.swing.ImageIcon("C:\\Users\\x\\Documents\\O.png"));
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jButton16.setIcon(new javax.swing.ImageIcon("C:\\Users\\x\\Documents\\118px-AMIGO.jpg"));
}
});
timer.setRepeats(false);
timer.start();
Soo created a timer using extending timertask.
label_1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
label_1.setVisible(false);
label_2.setVisible(true);
timer.purge();
class MyTimeTask extends TimerTask
{
public void run(){
genReelNumbers();
laa++;
if(laa==50){
timer.cancel();
timer.purge();
laa=0;
label_1.setVisible(true);
label_2.setVisible(false);}}}
timer.purge();
timer.schedule(new MyTimeTask(), 0, 50);}});
But im getting a error with the timer already canceled! As you can see i already tried to use the purge(), soo it cancels the "canceled" timers (dont know if that does make any sence). I want to use this timer each time that i press on the label! Any ideas?
First and foremost, this looks to be a Swing application, and if so, you shouldn't be using java.util.Timer and java.util.TimerTask since Swing is single-threaded, and the two classes above create a new thread or threads to achieve their actions, meaning that important code that should be called on the Swing event thread will not be called on this thread. This this risks causing pernicious intermittent and hard to debug threading exceptions to be thrown. Instead use a javax.swing.Timer. Then to stop this timer, simply call stop() on it, and to restart it, simply call start() on it. For more on this, please read: How To Use Swing Timers.
For example, I'm not 100% sure what you're code is supposed to be doing, but it could look something like:
// warning: code not compile- nor run-tested
label_1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
label_1.setVisible(false);
label_2.setVisible(true);
// assuming a javax.swing.Timer field named timer
if (timer != null && timer.isRunning()) {
// if the timer is not null and it's running, stop it:
timer.stop();
}
// TIMER_DELAY is an int constant that specifies the delay between "ticks"
timer = new Timer(TIMER_DELAY, new ActionListener() {
#Override // this method will be called repeatedly, every TIMER_DELAY msecs
public void actionPerformed(ActionEvent e) {
genReelNumbers();
laa++;
if(laa==50){
timer.stop();
// timer.purge();
laa=0;
label_1.setVisible(true);
label_2.setVisible(false);
}
}
});
timer.start();
}
});
after canceling the timer you have no other choice than creating a new object....
I followed the #Hovercraft advice and changed to javax.swing.Timer
It turned out like this:
//The variable "taxa" is the amount of times that i want it to do the task
javax.swing.Timer time1 = new javax.swing.Timer(taxa, new ActionListener() {
public void actionPerformed(ActionEvent e) {
genReelNumbers();
}
});
//starts the timer
time1.start();
//New timertask
TimerTask tt = new TimerTask() {
#Override
public void run() {
//stops the timer
time1.stop();
label_2.setVisible(false);
label_1.setVisible(true);
verificarodas();
}
};
Timer time = new Timer(true);
// the 2000 is how long i want to do the task's
//if i changed to 3000 it would take 3 seconds (remember it has to be a value on miliseconds) to do the 15 times, and soo on
time.schedule(tt, 2000);
I am trying to do the following: click a button, button disappears for 2 seconds, text appears for 2 seconds and after those 2 seconds the visibility is reversed. So far I have done this:
btnScan.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
txtScanning.setVisible(true);
btnScan.setVisible(false);
try {
Thread.sleep(2000); //1000 milliseconds is one second.
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
btnScan.setVisible(true);
}
});
and the result is that as soon as I click the btnScan, the whole program freezes for 2 seconds before doing anything. How do I add the delay at the correct order?
You should not call sleep method in your code that dispatches the event. All the work related UI is handled by EDT(Event Dispatch Thread) and a sleep method will cause it to freeze and hence your Swing application will freeze.
To overcome it you should use a Timer. Run the timer and execute the UI manipulation using SwingUtilities.invokeLater so that it is handled by EDT.
import java.util.Timer;
// make it a member variable
Timer timer = new Timer();
........
public void actionPerformed(java.awt.event.ActionEvent evt) {
button.setVisible(false);
timer.schedule(new TimerTask() {
#Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
button.setVisible(true);
}
});
}
}, 2000);
}
Currently in your code, you are causing the EDT (event dispatcher thread) to pause with the invocation of Thread.sleep
Performing any long running tasks in the EDT will cause your UI to freeze.
To achieve what you desire, use a SwingWorker thread to perform your actions
This might help: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Swing is a single threaded environment, anything that blocks this thread will prevent it from processing new events, including repaint requests.
Swing is also not thread safe, meaning img you should never create or update the UI from outside the context of the EDT.
In this case you can use a Swing Timer to trigger a callback to occur at some time in the future which (the notification) will be executed within the context of the EDT, making it safe to update the UI with
Take a look at Concurrency in Swing and How to us Swing Timers for more details
Making use of Swing timer, you can do something like this:
btnScan.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
txtScanning.setVisible(true);
btnScan.setVisible(false);
Timer timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent acv) {
btnScan.setVisible(true);
txtScanning.setVisible(false);
}
});
// setRepeats(false) to make the timer stop after sending the first event
timer.setRepeats(false);
timer.start();
}
});
In order to decrease server overload while searching,I'm going to provide delay for keyboard input.
use case:
1. user types symbols
2. if delay between typing symbols < 1 second,that search is NOT performed immediately and waiting when delay after last typed symbol is > 1second
3. if delay between typing symbols > 1 second,that search performed immediately
Is there best practises in JSE or in mobile Java(Blackberry)?
Looks like I should use TimerTask and Timer APIs for such case.Is it?
According to Java concurrency bible 'Java concurrency in practice'
... Timer has some drawbacks, and ScheduledThreadPoolExecutor should be thought of as its replacement.
Thus, I would do something like this example:
public class DelayedSearch extends JFrame {
public DelayedSearch() {
final JPanel panel = new JPanel(new BorderLayout());
final JTextField field = new JTextField(30);
panel.add(field, BorderLayout.NORTH);
final JLabel status = new JLabel(" ");
panel.add(status, BorderLayout.SOUTH);
this.add(panel);
this.pack();
final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
field.addKeyListener(new KeyAdapter() {
private ScheduledFuture<?> scheduled;
#Override
public void keyTyped(KeyEvent e) {
if (scheduled != null) scheduled.cancel(false);
scheduled = executor.schedule(new Runnable() {
#Override
public void run() { // Perform search here. Just set status for demo.
status.setText("Search: " + field.getText());
}
}, 1, TimeUnit.SECONDS);
}
});
}
public static void main(String[] args) {
new DelayedSearch().setVisible(true);
}
}
Note: I'm updating the status from a thread other than the EDT here which is illegal, but you get the idea.
EDIT: based upon great comments below (thanks!) Timer will work in this simple case, and it makes it easy to use a daemon thread (although it does have problems with tasks that throw exceptions, as described in the book). To do this replace above executor and listener as follows:
...
final Timer timer = new Timer(true); // use daemon thread.
field.addKeyListener(new KeyAdapter() {
private TimerTask task;
#Override
public void keyTyped(KeyEvent e) {
if(task != null)task.cancel();
task = new TimerTask() {
#Override
public void run() {
status.setText("Search: " + field.getText());
}
};
timer.schedule(task, 1000);
}
});
Yes, use a TimerTask. I would suggest an additional change to your rules: just make sure the requests are spaced at least a second, but don't wait till after the user stops typing for a second. Istead, immediately when the timout expires issue a new request with the input field state at that moment. The user may be in the middle of typing, but his experience with your app will be more fluid and responsive.
I'm trying to:
display a text in a jLabel,
wait for two seconds,
then write a new text in the jLabel
this should be simple, but I get a strange bug:
the first text is never written, the application just waits for 2 seconds and then displays the final text. here is the example code:
private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {
displayLabel.setText("Clicked!");
// first method with System timer
/*
long t0= System.currentTimeMillis();
long t1= System.currentTimeMillis();
do{
t1 = System.currentTimeMillis();
}
while ((t1 - t0) < (2000));
*/
// second method with thread.sleep()
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {}
displayLabel.setText("STOP");
}
with this code, the text "Clicked!" is never displayed. I just get a 2 seconds - pause and then the "STOP" text.
I tried to use System timer with a loop, or Thread.sleep(), but both methods give the same result.
Just to provide more background on Andrew Thompson's comment: the EDT is responsible for handling gui updates. If you block it using Thread.sleep(...) those updates are blocked as well. That's why you don't see the first text - the EDT just can't do the update on the label.
Here's a runnable example which does what you're after. As Andrew Thompson's comment stated, a SwingWorker is a good way to approach this problem.
The basic principal is to never block the Event Dispatch Thread. That's the thread responsible for repainting the GUI and responding to user interaction, so if you do something computationally expensive on the EDT, your GUI will stop responding.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
public class ButtonTest {
public static void main(String[] args) {
// create a frame and a button
JFrame frame = new JFrame();
final JButton button = new JButton("Button");
frame.add(button);
// add an action listener to the button
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// change the button text right away
button.setText( "Clicked" );
// create a SwingWorker which simply waits 2000 milliseconds
// simulating a computation being performed
SwingWorker<String, Object> worker = new SwingWorker<String, Object>() {
#Override
public String doInBackground() {
// it's safe to call Thread.sleep( ) here
// doInBackground is executed on a separate worker
// thread
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
return "Done";
}
#Override
protected void done() {
// done() is executed back on the Swing thread
// so it's safe to updated the state of the button
try {
button.setText(get());
} catch (Exception e) { }
}
};
// run the worker
worker.execute();
}
});
frame.setSize( 300, 300 );
frame.setVisible( true );
}
}
You are messing with the event dispatcher thread.
That will cause un-expected UI behavior as you are seeing. If you plan to do these type of animations, make sure to read up on what #Andrew Thompson suggested and also, see if you can read this - Filthy rich clients
Better to use a Swing Timer as shown in curde-example below:(yes, it is crude, I did not worry about stopping the timer etc):
public class DelayTest extends JPanel{
JLabel messageLabel = new JLabel();
JButton actionButton = new JButton("Click Me");
String[] messages = {"Clicked", "Stop!"};
int i=0;
public DelayTest(){
super();
add(messageLabel);
add(actionButton);
actionButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
if(i<=1)
messageLabel.setText(messages[i++]);
}
});
timer.start();
}
});
}
}
Edit
Why not stop the Timer:
#Override
public void actionPerformed(ActionEvent evt) {
if (i <= 1) {
messageLabel.setText(messages[i++]);
} else {
((Timer)evt.getSource()).stop();
}
}
});