I am trying to increment the value of a JTextfield (tenSecs) by one for every instance that my other JTextfield (oneSecs) reaches 0. I am having difficulty trying to increase the value of my tenSecs JTextfield as it is always 0. When manually changing the number, as soon as oneSecs reaches 0, tenSecs reverts to 0.
javax.swing.Timer tm = new javax.swing.Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
AddOneActionPerformed(evt);
}
});
private void StartStopTimerActionPerformed(java.awt.event.ActionEvent evt) {
if (!tm.isRunning()) {
tm.start();
} else {
tm.stop();
}
ScheduledExecutorService e= Executors.newSingleThreadScheduledExecutor(); //Start new scheduled executor service to invoke a timer that start wehn button is pressed
e.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
//Follow this Override to do task
SwingUtilities.invokeLater(new Runnable() {
//Override will let the task run
#Override
public void run() {
oneSecsDisplay.setIcon(new ImageIcon("images\\" + TextGrabber() + ".png"));
oneSecs.setText( DigitValue.getText());
int i = 0;
if (Integer.parseInt(oneSecs.getText()) == i) {
tenSecs.setText(Integer.toString(i++));
}
}
});
}
}, 0, 100, TimeUnit.MILLISECONDS); //Update will be for every 100 milliseconds concurrent to system time
}
// Variables declaration - do not modify
private javax.swing.JTextField oneSecs;
private javax.swing.JTextField tenSecs;
// End of variables declaration
I am sure that the error is occurring around the line int i = 0;. I am also sure that my way of increasing the value is not the best way to do this, if someone could kindly point me in the correct direction
If I'm understanding you correctly, try tenSecs.setText(String.valueOf(Integer.parseInt(tenSecs.getText()) + 1));
Related
I need to display output to a JTextArea one character at a time, with a slight delay between each character. My attempt is as follows:
private static void printInput(final String input)
{
Timer timer = new Timer(60,new ActionListener(){
public void actionPerformed(ActionEvent e)
{
for(int i = 0; i<input.length(); i++)
{
messageArea.append(Character.toString(input.charAt(i)));
}
}
});
}
There are similar questions however I could not find one with an example I could use to figure out my problem
A Timer is a pseudo loop, that it is, it triggers an cycle after a predefined delay, each cycle is an iteration of the loop and each iteration you need to update the UI and update the iterator value.
Now, because I don't like working in the static context, the first thing I suggest is you wrap up the basic concept into a separate class. This way you can easily encapsulate the state
public class TypeWriter {
private Timer timer;
private int characterIndex = 0;
private String input;
private JTextArea textArea;
public TypeWriter(JTextArea textArea, String input) {
this.textArea = textArea;
this.input = input;
timer = new Timer(60, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (characterIndex < input.length()) {
textArea.append(Character.toString(input.charAt(characterIndex)));
characterIndex++;
} else {
stop();
}
}
});
}
public void start() {
textArea.setText(null);
characterIndex = 0;
timer.start();
}
public void stop() {
timer.stop();
}
}
So, this is pretty basic, all this does is, using a Timer, check to see if there are any more characters that need to be printed, if there is, it takes the next character and appends it to the text area and updates the iterator value. If we're at the end of the text, it will stop the Timer (ie, the exit condition)
I've been working on a simple game using a Java Applet in which the player's goal is to get as many points as possible within a 30 second timeframe. Right now, I'm using a Swing timer to count down from 30 seconds, and once the 0 mark is reached, a "game over" screen is displayed with the player's score. I have these instance variables:
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
screenState = 0;
repaint();
}
};
Timer displayTimer = new Timer(30000, listener);
When the player clicks the "play" button, I execute displayTimer.start();.
Then, I have this within the appropriate case in my paint class:
g.drawString("Time Remaining: " + displayTimer.getDelay()/1000, 650, 100);
So, obviously, right now it's just displaying a static "Time Remaining: 30", and the screens switches after 30 seconds. What I'm trying to figure out is how I can repaint this value every one second so that it's a live timer. The only help I've been able to find thus far is for people use components.
ActionListener listener = new ActionListener() {
int count = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (count++==30) {
screenState = 0;
}
repaint();
}
};
Timer displayTimer = new Timer(1000, listener); // make it 30 times faster
You can use the a Thread that sleep it every one second using the sleep method of it
Here is a little sample that count to 30 with 1 second interval
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
int count = 0;
while(true)
{
if(count == 30) //end at 30 second
break;
try {
Thread.sleep(1000);
System.out.println("updated");
++count;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();
}
First of all, apologies for how long winded this is.
I'm trying to make a simple roulette game that allows a user to add players, place bets for these players, and spin the roulette wheel, which is represented as a simple JLabel that updates it's text with each number it passes.
However, I've run into a bug that I'm having a lot of trouble with: the JLabel only updates the text for the last element in my loop.
Basically, my solution works like this:
When a user presses a button labelled "Spin" (given that users have been added to the game), I call a method from a class called SpinWheelService, which is an Observable singleton which in turn calls the notifyObservers() method:
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
String description = null;
if (ADD_PLAYER.equals(cmd)) {
addDialog();
} else if (PLACE_BET.equals(cmd)) {
betDialog();
} else if (SPIN.equals(cmd)) {
SpinWheelService.sws.setSpinWheelService();
} else if (DISPLAY.equals(cmd)) {
System.out.println("Display selected!");
}
}
Here is my SpinWheelService class:
package model;
import java.util.*;
public class SpinWheelService extends Observable {
public static SpinWheelService sws = new SpinWheelService();
public void setSpinWheelService() {
setChanged();
notifyObservers();
}
}
The only listener registered for SpinWheelService is this class, where GameEngine is my game engine that handles internal game logic, WheelCallbackImpl is a class that updates the View:
class SpinWheelObserver implements Observer {
GameEngine gameEngine;
ArrayList<SimplePlayer> players;
WheelCallbackImpl wheelCall;
int n;
public SpinWheelObserver(GameEngine engine, WheelCallbackImpl wheel, ArrayList<SimplePlayer> playerList) {
players = playerList;
gameEngine = engine;
wheelCall = wheel;
}
public void update(Observable sender, Object arg) {
// check if any players are present
if (players.size() == 0) {
System.out.println("Empty player array!");
return;
}
do {
gameEngine.spin(40, 1, 300, 30, wheelCall);
n = wheelCall.playback();
} while (n== 0);
}
}
The main point of note here is my gameEngine.spin() method, which is this:
public class GameEngineImpl implements GameEngine {
private List<Player> playerList = new ArrayList<Player>();
// method handles the slowing down of the roulette wheel, printing numbers at an incremental delay
public void delay(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
System.out.println("Sleep method failed.");
}
}
public void spin(int wheelSize, int initialDelay, int finalDelay,
int delayIncrement, WheelCallback callback) {
Random rand = new Random();
int curNo = rand.nextInt(wheelSize) + 1;
int finalNo = 0;
assert (curNo >= 1);
// while loop handles how long the wheel will spin for
while (initialDelay <= finalDelay) {
delay(initialDelay);
initialDelay += delayIncrement;
// handles rotating nature of the wheel, ensures that if it reaches wheel size, reverts to 1
if (curNo > wheelSize) {
curNo = 1;
callback.nextNumber(curNo, this);
curNo++;
}
assert (curNo <= wheelSize);
callback.nextNumber(curNo, this);
curNo++;
finalNo = curNo - 1;
}
calculateResult(finalNo);
callback.result(finalNo, this);
}
The method callback.nextNumber(curNo, this):
public void nextNumber(int nextNumber, GameEngine engine) {
String strNo = Integer.toString(nextNumber);
assert (nextNumber >= 1);
System.out.println(nextNumber);
wcWheel.setCounter(strNo);
}
Where in, wcWheel is my singleton instance of my View, which contains the method setCounter():
public void setCounter(String value) {
label.setText(value);
}
Sorry for how convoluted my explanation is, but basically what it boils down to is that setCounter() is definitely being called, but seems to only call the setText() method on the final number. So what I'm left with is an empty label that doesn't present the number until the entire roulette has finished spinning.
I've determined that setCounter() runs on the event dispatch thread, and I suspect this is a concurrency issue but I have no idea how to correct it.
I've tried to include all relevant code, but if I'm missing anything, please mention it and I'll post it up as well.
I'm at my wits end here, so if anyone would be kind of enough to help, that would be so great.
Thank you!
Your while loop along Thread.sleep() will block and repainting or changing of the UI until the loop is finished.
Instead you'll want to implement a javax.swing.Timer for the delay, and keep a counter for the number of ticks, to stop it. You can see more at How to Use Swing Timers
The basic construct is
Timer ( int delayInMillis, ActionListener listener )
where delayInMillis is the millisecond delay between firing of an ActionEvent. This event is listened for by the listener. So every time the event is fired, the actionPerfomed of the listener is called. So you might do something like this:
Timer timer = new Timer(delay, new ActionListener()(
#Override
public void actionPerformed(ActionEvent e) {
if (count == 0) {
((Timer)e.getSource()).stop();
} else {
//make a change to your label
count--;
}
}
));
You can call timer.start() to start the timer. Every delay milliseconds, the label will change to what you need it to, until some arbitrary count reaches 0, then timer stops. You can then set the count variable to whatever you need to, if you want to to be random, say depending on how hard the wheel is spun :D
I think you didn't post all the relevant code that is required to know exactly the problem.
But most likely the problem is due to you run your loop and JLabel.setText() in the EDT (Event Dispatching Thread).
Note that updating the UI components (e.g. the text of a JLabel) also happens in the EDT, so while your loop runs in the EDT, the text will not be updated, only after your loop ended and you return from your event listener. Then since you modified the text of the JLabel it will be refreshed / repainted and you will see the last value you set to it.
Example to demonstrate this. In the following example a loop in the event listener loops from 0 to 9 and sets the text of the label, but you will only see the final 9 be set:
JPanel p = new JPanel();
final JLabel l = new JLabel("-1");
p.add(l);
JButton b = new JButton("Loop");
p.add(b);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for ( int i = 0; i < 10; i++ ) {
l.setText( "" + i );
try { Thread.sleep( 200 ); } catch ( InterruptedException e1 ) {}
}
}
} );
A proposed solution: Use javax.swing.Timer to do the loop's work. Swing's timer calls its listeners in the EDT so it's safe to update swing components in it, and once the listener returns, a component UI update can happen immediately:
JPanel p = new JPanel();
final JLabel l = new JLabel("-1");
p.add(l);
JButton b = new JButton("Loop");
p.add(b);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Timer(200, new ActionListener() {
int i = 0;
#Override
public void actionPerformed(ActionEvent e2) {
l.setText("" + i);
if ( ++i == 10 )
((Timer)e2.getSource()).stop();
}
}).start();
}
} );
In this solution you will see the label's text counting from 0 up to 9 nicely.
It's appears to me that your entire game must block in the action handler until the while loop has finished? So the text of the label will be getting updated but only the last update will be visible once the AWT thread is running again.
I am trying to create a simple Timer with a Start Stop and Reset Button. I am new to using the Threads and ActionListeners. I have this working, and can get my timer to begin, and my button to change text from start to stop. But after that i am stuck. I need to stop the timer, and then start it again, if i press the start button. Then of course reset turns it back to zero. I do not want to use java.util.Timer, i just want to use threads. How would i get my thread once started, to pause and then resume. I tried using the built in methods, but i could not get it to compile right.
import javax.swing.*;
import java.awt.Font;
import java.lang.String;
import java.awt.*;
public class Timer extends JPanel {
// Here are the fields from below!
private static JLabel label = new JLabel(" 0.00 seconds");
private static javax.swing.JButton start = new javax.swing.JButton("Start");
private static javax.swing.JButton reset = new javax.swing.JButton("reset");
/**
* Here is the Timer method- Begins with JLabel with medium alignment.
*/
public Timer() {
//new Thread(this).start();
//label = new JLabel(" 0.00 Seconds");
//this.label = label;
reset();
}
/**
* Here is the Reset method- pressing this button from below will
* stop the thread and reset the text.
*/
public static void reset() {
label.setFont(new Font("Arial",Font.BOLD,36));
label.setText(" 0.00 Seconds");
}
public static void startStop() {
//start.setText("stop");
//validate();
}
public static void countDown() {
int Msec=0,min=0,sec=0;
while(sec < 60) {
label.setText(min+":"+sec+":"+Msec);
//label.setLayout(new BorderLayout.CENTER);
//label.
Msec++;
if(Msec==60) {
Msec=0;
sec++;
//label.setText(min+":"+sec+":"+Msec);
}
if(sec ==60) {
Msec =0;
sec = 0;
min++;
}
try
{
Thread.sleep(10);
}
catch(Exception e)
{}
}
}
public static void main(String [] args) {
// we need a JFrame to put these elements into
javax.swing.JFrame win = new javax.swing.JFrame("Timer");
// here we are instantating a new timer
final Timer time = new Timer();
//Annonymous inner class
start.addActionListener(new java.awt.event.ActionListener() {
// here is the action performed method to start this.
public void actionPerformed(java.awt.event.ActionEvent e) {
//here we are creating a new thread to run throwable
// every click creates a new Thread ( so it goes faster)
String text = (String)e.getActionCommand();
if (text.equals("Start")){
start.setText("Stop");
}
else{
start.setText("Start");
}
Thread restart = new Thread(new Runnable() {
public void run() {
countDown();
//startStop();
}
});
restart.start();
}
});
//Look at the below abstract actionlistener below to get reset to work
javax.swing.JButton reset = new javax.swing.JButton("reset");
// here we are creating a new annonomys inner class.... check the
// curly braces
reset.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
Thread restart = new Thread(new Runnable() {
public void run() {
reset();
//Thread.stop();
}
});
restart.destroy();
}
});
//label.setVisible(true);
javax.swing.JPanel tb = new javax.swing.JPanel();
tb.add(reset);
tb.add(start);
//tb.add(circle);
win.add(tb,java.awt.BorderLayout.NORTH);
win.setSize(300,300);
//win.add(tb);
win.add(label,java.awt.BorderLayout.CENTER);
win.setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
// hiding inside setVisible is borderLayout
win.setVisible(true);
}
}
It is admirable and a great goal that you want to practice and improve with threads, but this really isn't the arena for it. The problem is that Swing is single threaded - only the ui thread should ever update the graphical environment.
For doing operations involving graphics you should use a javax.swing.Timer and javax.swing.SwingWorker, as these are Thread Safe. In one way, you are learning about thread safety here, so you are making progress!
I am making a simple target shooting game.I have a countdownTimer inside the label and an object that blinks in a random position inside the panel. Every time I click on the object,. the object's timer stops which makes that object stop too, but the countdown timer doesn't and that is my problem. I want the countdown timer should stop also.
Could someone help me about this matter?
Here's the code :
private void starting()
{
new Timer(TIMER_PERIOD, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if (count++ < MAX_COUNT)
{
String text = "Time remaining: (" + (MAX_COUNT - count) + ") seconds left";
setCountDownLabelText(text);
Date date = new Date();
setCountDownPanelText(date);
}
else
{
((Timer) e.getSource()).stop();
randomTimer.stop();
JOptionPane.showMessageDialog(null, "Game Over");
System.exit(0);
}
}
}).start();
}
It strikes me that you don't understand the code at all, that you are unaware of the anonymous class created that is extending Timer, which (if you'd seen the documentation) has a function stop() which does what you ask.
You need to store a reference to the Timer.
private javax.swing.Timer timer;
private void starting() {
timer = new Timer(TIMER_PERIOD, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// do stuff
// stop the timer
timer.stop();
// do other stuff
}
}
}