I want to use a Timer in a while loop. That is, I want to run the body of a while loop multiple times when it includes a timer within it. However, whenever I do this, the body of the while loop seems to execute and increment before the timer has fired the required amount of times. It is supposed to fire 15 times before the while loop increments, but it seems to be running through the while loop immediately before the timer fires the required amount of times, which I do not understand.
I know it isn't a problem with anything else because when I just run the code through once (i.e., without a while loop), it runs fine. The idea is that a JLabel is supposed to be removed and replaced every 1300ms until 15 images are displayed. Once it displays the 15 images, it moves onto the next row of the 2D array, of which there are 60 rows in total.
Any help would be appreciated. I have put the code below.
public class Game implements KeyListener, ActionListener{
private Preparation prep;
private Window window;
private JLabel earthLabel;
private JPanel panel;
private Timer timer;
private JLabel[] arrayOfAllSpaceshipsLabels;
private int[] arrayOfAllSpaceshipsIndexes;
private JLabel currentShipLabel;
private int numberOfBlocks;
private int firings;
private int[][] blocks = new int[60][15] //the values in this array have been initalized in another class that is too big and not relevant to my problem
public Game(){
window = new Window("Space Game");
runBlock();
}
private void runBlock() {
int blocksLength = blocks.length;
numberOfBlocks = 0;
while(numberOfBlocks < blocksLength){
firings = 0;
timer = new Timer(1333, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
if (firings == 15){
panel.removeAll();
panel.revalidate();
panel.repaint();
timer.stop();
System.out.println("Block finished");
return;
}
panel.removeAll(); /*(currentShipLabel);*/
panel.revalidate();
panel.repaint();
currentShipLabel = arrayOfAllSpaceshipsLabels[blocks[numberOfBlocks][firings]];
panel.add(currentShipLabel);
panel.validate();
firings++;
}
});
timer.start();
}
numberOfBlocks++;
}
}
public class Window extends JFrame{
private JPanel panel;
public Window(String title){
SwingUtilities.isEventDispatchThread();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//this.setBackground(Color.BLACK);
panel = new JPanel();
this.add(panel);
this.pack();
this.setSize(500,500); //my edit
panel.setBackground(Color.BLACK);
this.setVisible(true);
}
public JPanel getPanel() {
// TODO Auto-generated method stub
return panel;
}
}
As you have noticed, creating and starting a Timer does not prevent your loop from continuing.
To solve your problem you have to "move" your while loop into the timer action:
private void runBlock() {
int blocksLength = blocks.length;
numberOfBlocks = 0;
timer = new Timer(1333, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
if (firings == 15){
if (numberOfBlocks == blocksLength)
panel.removeAll();
panel.revalidate();
panel.repaint();
timer.stop();
System.out.println("Block finished");
return;
} else {
firings = 0;
numberOfBlocks++;
}
}
panel.removeAll(); /*(currentShipLabel);*/
panel.revalidate();
panel.repaint();
currentShipLabel = arrayOfAllSpaceshipsLabels[blocks[numberOfBlocks][firings]];
panel.add(currentShipLabel);
panel.revalidate();
firings++;
}
});
timer.start();
}
Related
I am trying to develop a very basic "Simon says" simulator using Java GUI. I have a method that generates and returns an int[] array; for each element in the array, the Timer computer should start, call the doClick() method for the specified JButton, and wait for 1/2 a second. Each JButton is connected to an ActionListener() that changes the color of the specific button to white, activates another Timer timer, and changes the button back to its original color.
Every time I call computer.start(); within the for-loop it runs the code within ComputerListener(), but it repeats endlessly. I have added print statements so that I can see what is going on via the output on Netbeans. I have looked at similar issues on the forum, but nothing has provided a viable solution.
My question: why is my ComputerListener class repeating when computer.start(); is called within the for-loop?
package simon;
// #jagged_prospect
import java.util.Random;
import java.util.Arrays;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.basic.BasicButtonUI;
public class SIMONPanel extends JPanel{
private static final int PANEL_W=300,PANEL_H=300;
private static final int PREF_W=500,PREF_H=500;
private static final String[] CARD_LABELS={"main","info","game"};
private final JPanel gameCard,infoCard,splashCard;
private final JButton rButton,yButton,gButton,bButton;
private final int lives=3;
private CardLayout cardlayout=new CardLayout();
private JPanel cards=new JPanel(cardlayout);
private Action[] actions={new ShowMainAction(),new ShowInfoAction(),
new ShowGameAction()};
private Object source;
private Timer timer,computer;
public SIMONPanel(){
setBackground(Color.BLACK);
setLayout(new BorderLayout());
gameCard=new JPanel();
infoCard=new JPanel();
splashCard=new JPanel();
// game card panel
gameCard.setLayout(new BorderLayout());
gameCard.setPreferredSize(new Dimension(PANEL_W,PANEL_H));
JPanel gameButtonPanel=new JPanel();
gameButtonPanel.setLayout(new GridLayout(2,2));
JButton startButton=new JButton("Start");
startButton.addActionListener(new StartListener());
rButton=new JButton("red");
rButton.addActionListener(new ColorButtonListener());
rButton.setSize(50,50);
rButton.setUI((ButtonUI)BasicButtonUI.createUI(rButton));
rButton.setBackground(Color.RED);
rButton.setForeground(Color.WHITE);
yButton=new JButton("yellow");
yButton.addActionListener(new ColorButtonListener());
yButton.setSize(50,50);
yButton.setUI((ButtonUI)BasicButtonUI.createUI(yButton));
yButton.setBackground(Color.YELLOW);
gButton=new JButton("green");
gButton.addActionListener(new ColorButtonListener());
gButton.setSize(50,50);
gButton.setUI((ButtonUI)BasicButtonUI.createUI(gButton));
gButton.setBackground(Color.GREEN);
bButton=new JButton("blue");
bButton.addActionListener(new ColorButtonListener());
bButton.setSize(50,50);
bButton.setUI((ButtonUI)BasicButtonUI.createUI(bButton));
bButton.setBackground(Color.BLUE);
bButton.setForeground(Color.WHITE);
gameButtonPanel.add(gButton);
gameButtonPanel.add(rButton);
gameButtonPanel.add(yButton);
gameButtonPanel.add(bButton);
gameCard.add(gameButtonPanel,BorderLayout.CENTER);
gameCard.add(startButton,BorderLayout.SOUTH);
// splash card panel
splashCard.setLayout(new BorderLayout());
splashCard.setPreferredSize(new Dimension(PANEL_W,PANEL_H));
splashCard.setBackground(Color.BLACK);
JLabel titleLabel=new JLabel("S I M O N",SwingConstants.CENTER);
titleLabel.setFont(new Font("Niagara Solid",Font.BOLD,84));
titleLabel.setForeground(Color.WHITE);
splashCard.add(titleLabel,BorderLayout.CENTER);
// info card panel
// nothing here yet
JPanel buttonPanel=new JPanel(new GridLayout(1,0,5,0));
for(Action action : actions){
buttonPanel.add(new JButton(action));
buttonPanel.setBackground(Color.BLACK);
}
cards.add(splashCard,CARD_LABELS[0]);
cards.add(infoCard,CARD_LABELS[1]);
cards.add(gameCard,CARD_LABELS[2]);
add(cards,BorderLayout.CENTER);
add(buttonPanel,BorderLayout.SOUTH);
}
// sets uniform panel size
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
// shows the Main Menu card
private class ShowMainAction extends AbstractAction {
public ShowMainAction() {
super("Main");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(cards,CARD_LABELS[0]);
}
}
// shows the Info card
private class ShowInfoAction extends AbstractAction {
public ShowInfoAction() {
super("Info");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(cards,CARD_LABELS[1]);
}
}
// show the Game card
private class ShowGameAction extends AbstractAction {
public ShowGameAction() {
super("Game");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(cards,CARD_LABELS[2]);
}
}
private class TimerListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent event){
if(source==gButton){
gButton.setBackground(Color.GREEN);
}
else if(source==rButton){
rButton.setBackground(Color.RED);
rButton.setForeground(Color.WHITE);
}
else if(source==yButton){
yButton.setBackground(Color.YELLOW);
}
else if(source==bButton){
bButton.setBackground(Color.BLUE);
bButton.setForeground(Color.WHITE);
}
}
}
private class ColorButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent event){
source=event.getSource();
int delay=300;
timer=new Timer(delay,new TimerListener());
if(source==gButton){
gButton.setBackground(Color.WHITE);
timer.setRepeats(false);
timer.start();
}
else if(source==rButton){
rButton.setBackground(Color.WHITE);
rButton.setForeground(Color.BLACK);
timer.setRepeats(false);
timer.start();
}
else if(source==yButton){
yButton.setBackground(Color.WHITE);
timer.setRepeats(false);
timer.start();
}
else if(source==bButton){
bButton.setBackground(Color.WHITE);
bButton.setForeground(Color.BLACK);
timer.setRepeats(false);
timer.start();
}
}
}
private class StartListener implements ActionListener{
public void actionPerformed(ActionEvent event){
// calls generateSequence() to make pattern for player to replicate
// for debugging in output
System.out.println(Arrays.toString(generateSequence()));
}
}
public int[] generateSequence(){
Random ran=new Random();
ComputerListener cpu=new ComputerListener();
computer=new javax.swing.Timer(500,cpu);
int seqLen=4;
int[] gameSequence=new int[seqLen];
for(int x=0;x<seqLen;x++){
int assign=ran.nextInt(4)+1;
gameSequence[x]=assign;
}
for(int y=0;y<seqLen;y++){ // print and wait 1/2 second, repeat 3 times
computer.start();
}
//computer.stop(); // should stop ComputerListener()???
return gameSequence;
}
private class ComputerListener implements ActionListener{
public void actionPerformed(ActionEvent event){
// for debugging in output
System.out.println("it worked");
}
}
}
You're calling the computer Swing Timer's start button multiple times in a for loop, and that is not what you want to do, and in fact, the whole purpose of the timer is to help you get rid of the for loop. Instead the Timer repeats an action, and changes a state, and keeps going until its done. Consider using an int array or better an ArrayList to hold the colors that the timer should iterate through, and within that ActionListener, do the action and advance a pointer to the next position in the array or List, using that pointer to decide what action to do next. Then when the pointer is completely through the collection, stop the Timer.
For an example of exactly what I'm describing, please check out my Timer's ActionListener for an incomplete Simon game here: Method keeps window from closing
The Timer's ActionListener, annotated, is below:
private class TimerListener implements ActionListener {
private SimonPanel simonPanel; // the Simon JPanel
private int colorListIndex = 0; // index into the ArrayList of MyColor objects
private int sliceCount = 0;
private List<MyColor> myColorList; // the MyColor ArrayList -- the random colors to press
private int maxCount;
public TimerListener(SimonPanel simonPanel, List<MyColor> myColorList) {
// pass in the key fields into the program via constructor parameter
this.simonPanel = simonPanel;
this.myColorList = myColorList; // again the ArrayList that holds random MyColor objects
maxCount = myColorList.size(); // size of my list
}
#Override
public void actionPerformed(ActionEvent evt) {
// if index at the end of the list -- get out and clean up
if (colorListIndex == maxCount) {
// clear the display of "pressed" colors
for (MyColor myColor : MyColor.values()) {
simonPanel.setMyColorPressed(myColor, false);
}
// stop this timer
((Timer) evt.getSource()).stop();
return;
}
// the listener is a little complex since it must turn on colors and turn them off
// which is why I use a sliceCount int counter variable here
if (sliceCount == 0) {
// turn on the next color in the list (using the index)
MyColor myColor = myColorList.get(colorListIndex);
simonPanel.setMyColorPressed(myColor, true);
sliceCount++;
} else if (sliceCount < TIME_SLICES - 1) {
sliceCount++;
return;
} else if (sliceCount == TIME_SLICES - 1) {
sliceCount = 0;
MyColor myColor = myColorList.get(colorListIndex);
simonPanel.setMyColorPressed(myColor, false); // turn off the color
colorListIndex++; // and increment the index
return;
}
}
}
I made a puzzle game in java Applet, and I need to add a timer that runs for 5 minutes where the player has to solve the puzzle within this time, if not a dialog box will appear asking to retry, so then I need the timer to start again.
Can someone tell me how can I code this.
public void init (){
String MINUTES = getParameter("minutes");
if (MINUTES != null) remaining = Integer.parseInt(MINUTES) * 600000;
else remaining = 600000; // 10 minutes by default
// Create a JLabel to display remaining time, and set some PROPERTIES.
label = new JLabel();
// label.setHorizontalAlignment(SwingConstants.CENTER );
// label.setOpaque(false); // So label draws the background color
// Now add the label to the applet. Like JFrame and JDialog, JApplet
// has a content pane that you add children to
count.add(label);
Puzframe.add(count,BorderLayout.SOUTH);
// Obtain a NumberFormat object to convert NUMBER of minutes and
// seconds to strings. Set it up to produce a leading 0 if necessary
format = NumberFormat.getNumberInstance();
format.setMinimumIntegerDigits(2); // pad with 0 if necessary
// Specify a MouseListener to handle mouse events in the applet.
// Note that the applet implements this interface itself
// Create a timer to call the actionPerformed() method immediately,
// and then every 1000 milliseconds. Note we don't START the timer yet.
timer = new Timer(1000, this);
timer.setInitialDelay(0); //
timer.start(); }
public void start() { resume(); }
//The browser calls this to stop the applet. It may be restarted later.
//The pause() method is defined below
void resume() {
// Restore the time we're counting down from and restart the timer.
lastUpdate = System.currentTimeMillis();
timer.start(); // Start the timer
}`
//Pause the countdown
void updateDisplay() {
long now = System.currentTimeMillis(); // current time in ms
long elapsed = now - lastUpdate; // ms elapsed since last update
remaining -= elapsed; // adjust remaining time
lastUpdate = now; // remember this update time
// Convert remaining milliseconds to mm:ss format and display
if (remaining < 0) remaining = 0;
int minutes = (int)(remaining/60000);
int seconds = (int)((remaining)/1000);
label.setText(format.format(minutes) + ":" + format.format(seconds));
label.setForeground(new Color(251,251,254));
label.setBackground(new Color(0,0,0));
// If we've completed the countdown beep and display new page
if (remaining == 0) {
// Stop updating now.
timer.stop();
}
count.add(label);
Puzframe.add(label,BorderLayout.SOUTH); }
This what I have so far, but my problem is that it doesn't appear in my game. I'm calling the updateDisplay() from actionPerformed
Use Swing Timer it is made for such a scenario
//javax.swing.Timer
timer = new Timer(4000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(mainFrame,
"End Of Game",
"5 minutes has passed",
JOptionPane.ERROR_MESSAGE);
}
});
I prepared a simple example to demonstrate it
Example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SwingControlDemo {
private JFrame mainFrame;
private JPanel controlPanel;
private Timer timer;
public SwingControlDemo(){
prepareGUI();
}
public static void main(String[] args){
SwingControlDemo swingControlDemo = new SwingControlDemo();
swingControlDemo.showEventDemo();
}
private void prepareGUI(){
mainFrame = new JFrame("Java SWING Examples");
mainFrame.setSize(400,400);
mainFrame.setLayout(new GridLayout(3, 1));
mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
System.exit(0);
}
});
controlPanel = new JPanel();
controlPanel.setLayout(new FlowLayout());
mainFrame.add(controlPanel);
mainFrame.setVisible(true);
//javax.swing.Timer
timer = new Timer(4000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(mainFrame,
"End Of Game",
"5 minutes has passed",
JOptionPane.ERROR_MESSAGE);
}
});
}
private void showEventDemo(){
JButton okButton = new JButton("Start Game");
okButton.setActionCommand("OK");
okButton.addActionListener(new ButtonClickListener());
controlPanel.add(okButton);
mainFrame.setVisible(true);
}
private class ButtonClickListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
timer.start();
String command = e.getActionCommand();
if( command.equals( "OK" )) {
System.out.println("Timer started");
}
}
}
}
I need a timer implemented in my application, which will do a countdown from 10 sec - 0 sec.
and, display the countdown in a JLabel.
Here's my implementation;
...
Timer t = new Timer(1000, new List());
t.start();
}
class List implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
int sec = 0;
label.setText(""+sec);
// Do a if- condition check to see if the clock has reached to, and then stop
}
}
I was expecting the JLabel to start counting from 0 - 10 and then stop. But it doesn't. The JLabel set the value 0 and it doesn't get incremented.
UPDATE 1
t = new Timer(1000, new Listner());
t.start();
}
class Listner implements ActionListener{
private int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
lable.setText(""+ (counter++));
if (counter == 10)
t.removeActionListener(this);
}
}
You are not storing nor incrementing secs anywhere so I don't see how it should get updated, try with
Timer timer;
void start() {
timer = new Timer(1000,new List());
}
class List implements ActionListener {
private counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
label.setText(""+counter++);
if (counter == 10)
timer.removeActionListener(this);
}
}
Mind that you need to store a reference to the timer somewhere to be able to remove the listener from it once countdown finished.
Well each time the timer is called it declares the int variable sec to 0. Hence the Label doesnt get updated.
You should declare the sec variable as a global variable and then in the actionPerformed method increment its value each time it is called.
public int sec = 0;
class List implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
sec++;
label.setText(""+sec);
// Do a if- condition check to see if the clock has reached to, and then stop
}
}
A complete example
public class ATimerExample {
Timer timer;
int counter = 0;
public ATimerExample() {
final JFrame frame = new JFrame("somethgi");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JLabel label = new JLabel("0");
JPanel panel = new JPanel();
panel.add(label, BorderLayout.SOUTH);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setText(String.valueOf(counter));
counter++;
if (counter == 10) {
//timer.removeActionListener(this);
timer.stop();
}
}
});
timer.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ATimerExample();
}
});
}
}
Since java reads the time in milliseconds, it should be 10000 instead of 1000. try your code and see if that works. I had the same problem when I wanted 30 seconds. And instead of writing Timer t = new Timer(30000, new List()); t.start();
I wrote Timer t = new Timer(3000, new List());
t.start();
That made my program to stop every after 3 seconds. I would suggest, you use 10000 instead of 1000.
Remember to do: t.stop() in your List class. Thanks
My first post, so forgive any incorrect etiquette. I'm currently doing my year end project for school and I need a bit of help. I am making a GUI java app in Netbeans. I have two classes. One is a class that controls a timer, the other is a class that is a scoreboard screen. I need to update the scoreboard timerLabel with the time that is being counted down in the timerClass. Its quite messy as there is another timer label in the Timer class which does update. My problem is that I cannot get timerLabel in MatchScreen() to update. Here is my code :
Timer Class
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class TimerClass extends JFrame {
Timer timer;
JLabel promptLabel, timerLabel;
int counter;
JTextField tf;
JButton button;
MatchScreen call = null;
public TimerClass() {
call = new MatchScreen();
setLayout(new GridLayout(4, 4, 7, 7));
promptLabel = new JLabel(""
+ "Enter number of seconds for the timer",
SwingConstants.CENTER);
add(promptLabel);
tf = new JTextField(5);
add(tf);
button = new JButton("Start");
add(button);
timerLabel = new JLabel("waiting...",
SwingConstants.CENTER);
add(timerLabel);
event e = new event();
button.addActionListener(e);
System.out.println("Button pressed");
}
public class event implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("Action performed");
int count = (int) (Double.parseDouble(tf.getText()));
timerLabel.setText("Time left: " + count);
call.setTimerLabel(count);
System.out.println("Passed count to tc");
TimeClass tc = new TimeClass(count);
timer = new Timer(1000, tc);
System.out.println("Timer.start");
timer.start();
//throw new UnsupportedOperationException("Not supported yet.");
}
/*public void actionPerformed(ActionEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}*/
}
public class TimeClass implements ActionListener {
int counter;
public TimeClass(int counter) {
this.counter = counter;
}
public void actionPerformed(ActionEvent e) {
counter--;
if (counter >= 1) {
call.setTimerLabel(counter);
} else {
timerLabel.setText("END");
timer.stop();
Toolkit.getDefaultToolkit().beep();
}
}
}
public static void main(String args[]) {
TimerClass gui = new TimerClass();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setSize(250, 150);
gui.setTitle("Time Setup");
gui.setVisible(true);
}
}
And now the ScoreBoard Screen
public class MatchScreen extends javax.swing.JFrame {
int redScore = 0, blueScore = 0, blueCat1 = 0,
blueCat2 = 0, redCat1 = 0, redCat2 = 0, winner = 0;
public MatchScreen() {
initComponents();
}
//Determine Winner of the match
public int getWinner() {
if (redScore > blueScore) {
winner = 1;
} else {
winner = 2;
}
return winner;
}
public void setTimerLabel(int a) {
int time = a;
while (time >= 1) {
timerLabel.setText("" + time);
}
if (time < 1) {
timerLabel.setText("End");
}
}
private void jButton13ActionPerformed(java.awt.event.ActionEvent evt) {
//Creates an object of the timerClass
TimerClass gui = new TimerClass();
gui.setSize(300, 175);
gui.setTitle("Time Setup");
gui.setVisible(true);
}
}
Some code that I felt is irrelevant was left out from the MatchScreen().
Many thanks
Managed to solve the general problem. I put all the code into one class. Not ideal, but it works :/ Anyway, deadlines are looming.
Sincere thanks.
You have a while loop in the setTimerLabel method, which I don't think you intended to put there. Also, you take the parameter a and assign it to time and then never use a again, why not just rename your parameter to time and bypass that additional variable?
EDIT
Sorry, I forgot to explain what I'm seeing :P If you say call.setTimerLabel(10) then you hit that while loop (while(time >= 1) which is essentially running while(10 >= 1) which is an infinite loop. Your program is never leaving the method setTimerLabel the first time you call it with a value >= 1.
I've got a "status" JLabel in one class (named Welcome) and the timer in another one (named Timer). Right now, the first one displays the word "status" and the second one should be doing the countdown. The way I would like it to be, but don't know how to - display 10, 9, 8, 7 ... 0 (and go to the next window then). My attempts so far:
// class Welcome
setLayout(new BorderLayout());
JPanel area = new JPanel();
JLabel status = new JLabel("status");
area.setBackground(Color.darkGray);
Font font2 = new Font("SansSerif", Font.BOLD, 25);
status.setFont(font2);
status.setForeground(Color.green);
area.add(status, BorderLayout.EAST); // can I put it in the bottom-right corner?
this.add(area);
and the timer:
public class Timer implements Runnable {
// public void runThread() {
// new Thread(this).start();
// }
public void setText(final String text) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setText(text); // link to status here I guess
}
});
}
public void run() {
for (int i = 10; i > 0; i--) {
// set the label
final String text = "(" + i + ") seconds left";
setText(text);
// // sleep for 1 second
// try {
// Thread.currentThread();
// Thread.sleep(1000);
// } catch (Exception ex) {
// }
}
// go to the next window
UsedBefore window2 = new UsedBefore();
window2.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// runThread();
}
} // end class
I agree that you should consider using a "Java" Timer as per Anh Pham, but in actuality, there are several Timer classes available, and for your purposes a Swing Timer not a java.util.Timer as suggested by Anh would suit your purposes best.
As for your problem, it's really nothing more than a simple problem of references. Give the class with the label a public method, say setCountDownLabelText(String text), and then call that method from the class that holds the timer. You'll need to have a reference of the GUI class with the timer JLabel in the other class.
For example:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Welcome extends JPanel {
private static final String INTRO = "intro";
private static final String USED_BEFORE = "used before";
private CardLayout cardLayout = new CardLayout();
private JLabel countDownLabel = new JLabel("", SwingConstants.CENTER);
public Welcome() {
JPanel introSouthPanel = new JPanel();
introSouthPanel.add(new JLabel("Status:"));
introSouthPanel.add(countDownLabel);
JPanel introPanel = new JPanel();
introPanel.setPreferredSize(new Dimension(400, 300));
introPanel.setLayout(new BorderLayout());
introPanel.add(new JLabel("WELCOME", SwingConstants.CENTER), BorderLayout.CENTER);
introPanel.add(introSouthPanel, BorderLayout.SOUTH);
JPanel usedBeforePanel = new JPanel(new BorderLayout());
usedBeforePanel.setBackground(Color.pink);
usedBeforePanel.add(new JLabel("Used Before", SwingConstants.CENTER));
setLayout(cardLayout);
add(introPanel, INTRO);
add(usedBeforePanel, USED_BEFORE);
new HurdlerTimer(this).start();
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Welcome");
frame.getContentPane().add(new Welcome());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
public void setCountDownLabelText(String text) {
countDownLabel.setText(text);
}
public void showNextPanel() {
cardLayout.next(this);
}
}
class HurdlerTimer {
private static final int TIMER_PERIOD = 1000;
protected static final int MAX_COUNT = 10;
private Welcome welcome; // holds a reference to the Welcome class
private int count;
public HurdlerTimer(Welcome welcome) {
this.welcome = welcome; // initializes the reference to the Welcome class.
String text = "(" + (MAX_COUNT - count) + ") seconds left";
welcome.setCountDownLabelText(text);
}
public void start() {
new Timer(TIMER_PERIOD, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (count < MAX_COUNT) {
count++;
String text = "(" + (MAX_COUNT - count) + ") seconds left";
welcome.setCountDownLabelText(text); // uses the reference to Welcome
} else {
((Timer) e.getSource()).stop();
welcome.showNextPanel();
}
}
}).start();
}
}
Since you're using Swing you should use the javax.swing.Timer, not the java.util.Timer. You can set the timer to fire at 1 second (1000 ms) intervals and have your listener do the updating. Since Swing updates must take place in the event dispatch thread your listener is the perfect place for status.setText.
there's already a Timer class in java: http://www.exampledepot.com/egs/java.util/ScheduleRepeat.html
Why not put the setText method in the welcome class and just do 'status.setText(text)'?
And you might try BorderLayout.SOUTH or .PAGE END or .LINE END to get the timer in the lower right corner