How Could I Add a Simple Delay in a Java Swing Application

How could I add a simple delay in a Java Swing application?

Here's an example using a javax.swing.Timer

public class TestBlinkingText {

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new BlinkPane());
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

protected static class BlinkPane extends JLabel {

private JLabel label;
private boolean state;

public BlinkPane() {

label = new JLabel("Look at me!");
setLayout(new GridBagLayout());

add(label);

Timer timer = new Timer(500, new ActionListener() {

@Override
public void actionPerformed(ActionEvent ae) {
state = !state;
if (state) {
label.setForeground(Color.RED);
} else {
label.setForeground(Color.BLACK);
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.setInitialDelay(0);
timer.start();
}
}
}

Any way to delay actions in a Java GUI

Not looking to use Thread.sleep() as it doesn't work well with gui.

Good, use a Swing Timer instead

I want the pokerHand.setVisibility(true), and other methods in my code to execute AFTER the delay, ( using a timer doesn't do this ).

Yes it does, you're just not using it properly, but since you've not provided any actual code, I can't say "how" you're not using it properly, only from the sounds of it, you are.

Start by taking a look at How to use Swing Timers for more details

The following is very simple example, it uses a Timer to calculate and print the amount of time between the time you clicked the button.

The example updates the UI AFTER the Timer is started, but until the Timer completes, the calculation and result are not generated

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalTime;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

public static void main(String[] args) {
new Test();
}

public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel {

private JTextArea ta;
private JButton btn;

private Timer timer;

private LocalTime startTime, endTime;

public TestPane() {
setLayout(new BorderLayout());
ta = new JTextArea(10, 20);
add(new JScrollPane(ta));
btn = new JButton("Click");
add(btn, BorderLayout.SOUTH);

timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
endTime = LocalTime.now();
Duration duration = Duration.between(startTime, endTime);
ta.append("Ended @ " + endTime + "\n");
ta.append("Took " + (duration.toMillis() / 1000) + " seconds\n");
}
});
timer.setRepeats(false);

ta.setEditable(false);

btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
timer.start();
startTime = LocalTime.now();
btn.setEnabled(false);
ta.append("Start @ " + startTime + "\n");
}
});
}

}

}

how can i have a delay on my interface (java swing) using Java Swing Timer?

You're almost there. But you seem to be misunderstanding what the Timer is actually doing for you.

The Timer is acting as a kind of pseudo loop, with a built in delay. That is, after each time period, it will execute. This means, that each time your ActionListener is triggered, you want to execute the next step in your logic.

For example...

Sample Image

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;

public class Main {
public static void main(String[] args) {
new Main();
}

public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel {

private JPanel contentPane = new JPanel(new GridBagLayout());

public TestPane() {
setLayout(new BorderLayout());
add(new JScrollPane(contentPane));

JButton startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
private int row = 0;
private int count = 1000;
private DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
@Override
public void actionPerformed(ActionEvent e) {
row = 0;
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
gbc.weightx = 1;
contentPane.removeAll();
contentPane.revalidate();
contentPane.repaint();

Timer timer = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
row++;
if (row >= count) {
((Timer)(e.getSource())).stop();
return;
}

JLabel label = new JLabel(LocalDateTime.now().format(formatter));
contentPane.add(label, gbc);
contentPane.revalidate();
contentPane.repaint();
// This is only required because the layout pass seems
// to be execute in different run cycle, so the label's
// bounds are not been updated yet. We force the layout
// pass so we can scroll to the label, but otherwise
// isn't needed
contentPane.doLayout();
Rectangle bounds = label.getBounds();
bounds.y += bounds.height;
contentPane.scrollRectToVisible(bounds);
}
});
timer.start();
}
});
add(startButton, BorderLayout.NORTH);
}

@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}

How to use a delay in a swing application

Take a look at: https://timingframework.dev.java.net/

and the samples that come in http://filthyrichclients.org/

They provide some very good information on how animation work and using the Timer framework. You'll have a good understanding of how it works.

I did a sample animation here with Swing after reading those:

count down demo app http://img580.imageshack.us/img580/742/capturadepantalla201004wd.png
Java application featuring blog.stackoverflow.com page ( click on image to see the demo video )

But I'm not even sure what is what you want to achieve.

EDIT

I read about the timing framework to understand better what is all about, but I actually didn't use it ( it is useful to create animations with no linear times - ie no every second as mine, but things like 1, 5, 3, 2 seconds )

The code I'm using in the demo above is exactly this:

final Timer imageTimer = new Timer();
imageTimer.schedule( new TimerTask() {
public void run() {
changeImage();
}
}, 0, 10000 ); //<-- every 10 seconds.

The animation for the "stackoverflowing" and the count down use a similar approach.

How to delay an answer while not freezing the thread?

Consider using a Timer to prevent main thread from freezing :

import javax.swing.*;
import java.awt.event.*;

ActionListener task = new ActionListener() {
public void actionPerformed(ActionEvent evt) {

}
};
Timer countdown = new Timer(1000 ,task);
countdown.setRepeats(false);
countdown.start();

where 1000 is the delay time in milliseconds and inside the actionPerformed function is where your code executes after the delay time set.

How to create a delay in Swing

Well, the following code shows a JFrame with a JTextArea and a JButton. When the buttons is clicked, the Timer send the event repeatedly (with a second delay between them) to the actionListener related to the button which appends a line with the current time.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;

public class TimerTest extends JFrame implements ActionListener{

private static final long serialVersionUID = 7416567620110237028L;
JTextArea area;
Timer timer;
int count; // Counts the number of sendings done by the timer
boolean running; // Indicates if the timer is started (true) or stopped (false)

public TimerTest() {
super("Test");
setBounds(30,30,500,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);

area = new JTextArea();
area.setBounds(0, 0, 500, 400);
add(area);

JButton button = new JButton("Click Me!");
button.addActionListener(this);
button.setBounds(200, 400, 100, 40);
add(button);

// Initialization of the timer. 1 second delay and this class as ActionListener
timer = new Timer(1000, this);
timer.setRepeats(true); // Send events until someone stops it
count = 0; // in the beginning, 0 events sended by timer
running = false;
System.out.println(timer.isRepeats());
setVisible(true); // Shows the frame
}

public void actionPerformed(ActionEvent e) {
if (! running) {
timer.start();
running = true;
}
// Writing the current time and increasing the cont times
area.append(Calendar.getInstance().getTime().toString()+"\n");
count++;
if (count == 10) {
timer.stop();
count = 0;
running = false;
}
}

public static void main(String[] args) {
// Executing the frame with its Timer
new TimerTest();
}
}

Well, this code is a sample of how to use javax.swig.Timer objects. In relation with the particular case of the question. The if statement to stop the timer must change, and, obviously, the actions of the actionPerformed. The following fragment is a skeleton of the solution actionPerformed:

public void actionPerformed(ActionEvent e) {
if (e.getComponent() == myDealerComponent()) {
// I do this if statement because the actionPerformed can treat more components
if (! running) {
timer.start();
runnig = true;
}
// Hit a card if it must be hitted
switch (getJBTable(JB.total, JB.aces > 0)) {
case 0:
JB.hit();
break;
case 1:
break done;
case 2:
JB.hit();
JB.bet *= 2;
break done;
}
if (JB.total >= 21) { // In this case we don't need count the number of times, only check the JB.total 21 reached
timer.stop()
running = false;
}

}
}

IMHO this resolves the problem, now @user920769 must think where put the actionListener and the starting/stopping conditions...

@kleopatra: Thanks for show me the existence of this timer class, I don't know nothing about it and it's amazing, make possible a lot of tasked things into a swing application :)

Simple Swing Delay

If your code modifying your Swing component's state is on the EDT here (it should be), then no repainting of the label with the first text will take place even if you do call repaint(), because all other EDT requests queued before the last repaint need to complete before you reach that repaint, and your code here is one of those queued EDT events.

If you call repaint, it adds a repaint to the queue, it doesn't repaint right away. Your actions here will result in a 5 second wait, with the label before the next repaint having only the text you last set it to (as code queued on the EDT is executed fully before going to what next is queued).

Try using a Swing Timer, events fired from the Swing Timer are already executing on the EDT, so it's pretty much what you need, one event here where you set the text initially, and another event fired by the Swing Timer to change the text after 5 seconds.

Edit, example of Swing Timer firing once, after 5 seconds as requested by author:

    // set first jlabel text here

ActionListener task = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("This is on the EDT after 5 seconds, " +
"well depending on if I'm used with a Timer, and if " +
"the right options are set to that Timer");
// set second jlabel text here
}
};
Timer timer = new Timer(5000 , task);
timer.setRepeats(false);
timer.start();

How to add delay inside a JTextArea in displaying text?

You can use a Timer, all you have to do is:

1) import

import javax.swing.Timer;

2) initialise with his own Action Listener

private int i = 0;
private Timer tmr = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
textArea.append(" .");
++i;
if(i >= 2)
tmr.stop();
}
});

3) start your timer with:

tmr.start();

This should work.
Let me know if there is any issue.



Related Topics



Leave a reply



Submit