I have a save button in a JFrame ;on clicking save the 'save' text sets to 'saving....'; I need to set that text as 'saved' after a delay of 10 seconds.How is it possible in java?
Please help...
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
This is what i did...but this wont shows as 'saving' during that delayed time.
If you want to provide the user with visual feedback that something is going on (and maybe give some hint about the progress) then go for JProgressBar and SwingWorker (more details).
If on the other hand you want to have a situation, when user clicks the button and the task is supposed to run in the background (while the user does other things), then I would use the following approach:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false); // change text if you want
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the calculations
// Wait if you want
Thread.sleep(1000);
// Dont touch the UI
return null;
}
#Override
protected void done() {
try {
get();
} catch (Exception ignore) {
} finally {
button.setEnabled(true); // restore the text if needed
}
}
}.execute();
}
});
Finally, the initial solution that was using the Swing specific timer:
final JButton button = new JButton("Save");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Take somehow care of multiple clicks
button.setText("Saving...");
final Timer t = new Timer(10000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
button.setText("Saved");
}
});
t.setRepeats(false);
t.start();
}
});
This question & first 3 answers are heading down the wrong track.
Use a JProgressBar to show something is happening. Set it to indeterminate if the length of the task is not known, but presumably you know how much needs to be saved and how much is currently saved.
Don't block the EDT (Event Dispatch Thread) - the GUI will 'freeze' when that happens. Use a SwingWorker for long running tasks. See Concurrency in Swing for more details.
The best is to use a timer and its method execute with a delay : http://developer.apple.com/library/mac/documentation/java/reference/javase6_api/api/java/util/Timer.html#schedule(java.util.TimerTask, long). Use a timertask to wrap your runnable and that's it.
Related
Having a "next" Button, when I press keyboard enter key with the button selected, the widgetSelected event of the button is being repeatedly called once and once and doing a super fast next. It's exactly the behaviour I want, but only happens with keyboard enter key.
I want to have that behaviour with mouse click when holding the click. When trying to do the same with the mouse click, the behaviour is not the same, it only makes one event call, and when the click is end (UP). How to simulate the same behaviour with the mouse click?
I tried it doing this, but it blocks the UI (can't understand why) and mouseUp is never being called, it blocks forever in the while:
button.addMouseListener(new MouseAdapter() {
boolean mouseDown;
#Override
public void mouseDown(MouseEvent e) {
System.out.println("mouseDown");
mouseDown = true;
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
while (mouseDown) {
System.out.println("Doing next in mouseDown");
next(composite, label_1);
synchronized(this){
try {
wait(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
}
#Override
public void mouseUp(MouseEvent e) {
System.out.println("mouseUp");
mouseDown = false;
}
});
The Runnable you give to asyncExec runs in the UI thread. You must never do any sort of wait in the UI thread as that will block the UI until it completes.
So you cannot run a loop like this as it just blocks the UI. Since the loop never returns to the main SWT readAndDispatch loop no UI actions are done.
Instead use the timerExec method of Display to schedule a Runnable to run after a given interval. This runnable should do one step of the action and use timerExec to schedule the next step later.
I remember there was another question a few days ago regarding a long mouse click behaviour but I can't find it anymore. I put this code based on greg-449 solution to use timerExec method, after my failed attempts to use asyncExec in the UI thread. :)
button.addMouseListener(new MouseAdapter() {
boolean mouseDown;
#Override
public void mouseDown(MouseEvent e) {
mouseDown = true;
Display.getCurrent().timerExec(1000, () -> {
if (mouseDown) {
button.notifyListeners(SWT.Selection, new Event());
button.notifyListeners(SWT.MouseDown, new Event());
}
});
}
#Override
public void mouseUp(MouseEvent e) {
mouseDown = false;
}
});
button.addSelectionListener(SelectionListener.widgetSelectedAdapter(
e -> System.out.println("Do next")));
Is there a way to easily convert thread.sleep to javax.swing.timer?
The reason why I would need to do this, is to stop the user-interface from freezing when you press a button, so that you can implement a pause button.
Code Example:
btnStartTiming.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent arg0) {
try{
inputA = Double.parseDouble(txtEnterHowLong.getText()); //Changes double to string and receives input from user
}catch(NumberFormatException ex){
}
while (counter <= inputA){
txtCounter.setText(counter + "");
try {
Thread.sleep(1000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
System.out.println(counter);
counter++;
}
}
});
Some tips:
Take a look to How to use Swing
Timers
trail and come back with concrete problems. Describe what are you trying to accomplish and your work so far, show your attempts to solve the problem and make an answerable question.
Don't use MouseListener
to listen when a button is pressed. Use ActionListener
instead. Take a look to How to Use Buttons, Check Boxes, and Radio
Buttons trail.
Put the java.swing.Timer in your constructor. You can use the button to .start() the timer.
Also instead of the while, you can add an if statement in the timer code check when to .stop()
Something like this
int delay = 1000;
Timer timer = new Timer(delay, null);
public Constructor(){
timer = new Timer(delay, new ActionListener(){
public void actionPerformed(ActionEvent e) {
if (counter >= inputA) {
timer.stop();
} else {
// do something
}
}
});
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
}
I'm creating a java program that involves a button that gives a bunch of problems. I'm wondering how can I create a delay between the times a user can click a button (to prevent button spamming). Here is what I tried.
public void ButtonActionPerformed(java.awt.event.ActionEvent evt) {
Thread DelayTHREAD = new Delay();
if(DelayTHREAD.isAlive()) {
/*do nothing*/
}
else {
/*some other code*/
DelayTHREAD.start();
}
}
public static class Delay extends Thread /*Prevents user from spamming buttons*/ {
#Override
public void run() {
try {
Thread.sleep(5000); /*sleeps for the desired delay time*/
}catch(InterruptedException e){
}
}
}
OK so here is the problem, it doesn't matter whether or not the delay thread is started or not, the program still goes on and continues to perform the action performed as if the delay thread never even existed.
Someone please tell me how can I create a delay, so that a user cannot spam button in a program? Thanks :)
You might just create a little method that disables the button for a period of time after the user clicks on it, and then enables it afterward, like so:
static void disable(final AbstractButton b, final long ms) {
b.setEnabled(false);
new SwingWorker() {
#Override protected Object doInBackground() throws Exception {
Thread.sleep(ms);
return null;
}
#Override protected void done() {
b.setEnabled(true);
}
}.execute();
}
Then call it from your actionPerformed method like this:
disable(button, 5000);
Just make sure you call it from the EDT.
Use a SwingTimer to inject a delay between the button click and the activation of the associated action....
import javax.swing.Timer;
/*...*/
private Timer attackTimer;
/*...*/
attackTimer = new Timer(5000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Do attack...
}
});
attackTimer.setRepeats(false);
/*...*/
public void ButtonActionPerformed(java.awt.event.ActionEvent evt) {
// Restart the timer each time the button is clicked...
// In fact, I would disable the button here and re-enable it
// in the timer actionPerformed method...
attackTimer.restart();
}
I have a jList called todoList
When the user click on an item in the list, it stays selected. But I would like the currently selected item in the list to deselect "by itself" after 400 milliseconds when the mouse exits the jList.
This must only run if there is something already selected in the list.
I am using Netbeans IDE and this is what is have tried so far:
private void todoListMouseExited(java.awt.event.MouseEvent evt) {
if (!todoList.isSelectionEmpty()) {
Thread thread = new Thread();
try {
thread.wait(400L);
todoList.clearSelection();
} catch (InterruptedException ex) {
System.out.println(ex);
}
}
}
and
private void todoListMouseExited(java.awt.event.MouseEvent evt) {
if (!todoList.isSelectionEmpty()) {
Thread thread= Thread.currentThread();
try {
thread.wait(400L);
todoList.clearSelection();
} catch (InterruptedException ex) {
System.out.println(ex);
}
}
}
These both just make everything stop working.
My though process was that i need to create a new Thread that will wait for 400 milliseconds and then run the clearSelection() method of the jList. This would happen every time the mouse exits the list and run only if there is something in the list that is already selected.
I hope I am explaining my problem thoroughly enough.
The problem is that you are blocking the AWT-Event-Thread.
The solution is to use a swing timer:
private void todoListMouseExited(java.awt.event.MouseEvent evt)
{
if (!todoList.isSelectionEmpty()) {
new Timer(400, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
todoList.clearSelection();
}
}).start();
}
}
The problem is that Object#wait is waiting(rather than sleeping) to be notified but this is not happening. Instead the timeout causing an InterruptedException bypassing the call to clearSelection.
Don't use raw Threads in Swing applications. Instead use a Swing Timer which was designed to interact with Swing components.
if (!todoList.isSelectionEmpty()) {
Timer timer = new Timer(400, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
todoList.clearSelection();
}
});
timer.setRepeats(false);
timer.start();
}
Basically, I have this game where once guesses the correct answer it starts a new game with a new word. I want to display Correct! but after three seconds, change it to a empty string. How do I do that?
My attempt:
if (anagram.isCorrect(userInput.getText()))
{
anagram = new Anagram();
answer.setText("CORRECT!");
word.setText(anagram.getRandomScrambledWord());
this.repaint();
try
{
Thread.currentThread().sleep(3000);
}
catch (Exception e)
{
}
answer.setText("");
} else
{
answer.setForeground(Color.pink);
answer.setText("INCORRECT!");
}
Edit:
My solution:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
// TODO add your handling code here:
if (anagram.isCorrect(userInput.getText()))
{
answer.setText("CORRECT!");
ActionListener taskPerformer = new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
anagram = new Anagram();
word.setText(anagram.getRandomScrambledWord());
answer.setText("");
userInput.setText("");
}
};
Timer timer = new Timer(3000, taskPerformer);
timer.setRepeats(false);
timer.start();
} else
{
answer.setForeground(Color.pink);
answer.setText("INCORRECT!");
}
}
I am not sure, but I hope that I am following MadProgrammer's advice and not blocking the event itself, but the new thread. I will look up Java Timer also.
Swing is an event driven environment. While you block the Event Dispatching Thread, no new events can be processed.
You should never block the EDT with any time consuming process (such as I/O, loops or Thread#sleep for example).
You might like to have a read through The Event Dispatch Thread for more information.
Instead, you should use a javax.swing.Timer. It will trigger a ActionListener after a given delay.
The benefit of which is that the actionPerformed method is executed with the context of the Event Dispatching Thread.
Check out this or this or this or this for an examples
it works after 3 seconds..
ActionListener taskPerformer = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
statusbar.setText("Status");
}
};
Timer timer = new Timer(3000, taskPerformer);
timer.setRepeats(false);
timer.start();
if these piece of code is in the event handlers, then you are holding up the UI thread, and it is not going to work as UI update will only happens after you finished your work in the event handlers.
You should create another thread do the work of "sleep 3 second, and change the text field, and trigger repaint". Using Timer or similar utilities is the easiest way to achieve what I am describing.