Resetting a new thread repetitively - java

In my program, there is a button, "Display", and another button, "Reset".
The user enters the number of prime numbers they want in the text field and then clicks the "Display" button. Then, the first x prime numbers will appear in the text area.
In the code, I have:
Declarations:
Thread go;
Thread newThread;
JLabel howManyLabel;
JTextField howMany;
JButton display;
JButton reset;
JTextArea primes;
Action Event:
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == display) {
display.setEnabled(false);
if (go == null) {
go = new Thread(this);
go.start();
} else {
newThread = new Thread(this);
newThread.start();
}
} else if (source == reset) {
display.setEnabled(true);
howMany.setText(" ");
primes.setText(" ");
}
}
Run method:
public void run() {
int quantity = Integer.parseInt(howMany.getText());
int numPrimes = 0;
int candidate = 2; // candidate = the number that MIGHT be prime
primes.append("First " + quantity + " primes:");
while(numPrimes < quantity) {
if (isPrime(candidate)) {
primes.append(candidate + ", ");
numPrimes++;
}
candidate++;
}
}
The run() method is in the same class, and simply calculates the first x amount of prime numbers.
I am trying to create a new thread every time the "Reset" button is called. The thread runs the first time, but then does not run again after I click "Reset". Can the run() method only work once?
Thanks in advance.

The run() method is just like any other method and can be invoked any number of times. The method that cannot be invoked multiple times is start()(according to Thread).
Your explanation does not seem to fit with the code you gave. You say you want to spawn a new thread when a user clicks reset, yet you only construct or start threads if the source is Display. Did you mean, rather, that you want to cancel the last thread and enable controls for the user to start again? In that case you should use a Future, not a generic thread.
Another thing is that UI components are generally not thread-safe. Swing explicitly warns against it on every components JavaDoc. What you may be seeing is just components not updating their visible state when they are changed from a different thread. Have you tried using a debugger to see if a thread is actually not getting spawned, or it is being spawned, but not having the result you want?

Related

Guess Number Game GUI - Infinite Loop

I'm making a guess the number program and I'm having trouble with my loop. When I run the program and input a number into the textfield and hit enter it freezes. I figured out that this might be happening because of an infinite loop. Feel free to correct me if I'm wrong. Basically when I enter a number into the textfield and press enter it suppose to change a label and change background color but this doesn't happen and I think its because my loop runs until win becomes true and when I type in my number it keeps running that number instead of outputting the correct label and letting me input a different number into the textfield. P.S: I know the newGame button does not work yet
import java.util.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class GuessingGame implements ActionListener
{
JFrame guessFrame;
JPanel guessPanel;
JTextField guessText;
JButton newGame;
JLabel rangeLbl, enterGuessLbl, winLbl;
Random rand = new Random();
int numToGuess = rand.nextInt(1000)+1;
int numOfTries = 0;
int guess;
public GuessingGame()
{
// Create the frame and container.
guessFrame = new JFrame("Guess the Number");
guessPanel = new JPanel();
guessPanel.setLayout(new GridLayout(5,0));
// Add the widgets.
addWidgets();
// Add the panel to the frame.
guessFrame.getContentPane().add(guessPanel, BorderLayout.CENTER);
// Exit when the window is closed.
guessFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Show the converter.
guessFrame.pack();
guessFrame.setVisible(true);
}
// Create and add the widgets for converter.
private void addWidgets()
{
// Create widgets.
guessText = new JTextField();
guessText.setHorizontalAlignment(JTextField.CENTER);
rangeLbl = new JLabel("I have a number between 1 and 1000. Can you guess my number?", SwingConstants.LEFT);
enterGuessLbl = new JLabel("Please enter your guess", SwingConstants.LEFT);
winLbl = new JLabel(" ", SwingConstants.CENTER);
newGame = new JButton("New Game");
// Listen to events from Convert textfield.
guessText.addActionListener(this);
// Add widgets to container.
guessPanel.add(rangeLbl);
guessPanel.add(enterGuessLbl);
guessPanel.add(guessText);
guessPanel.add(winLbl);
guessPanel.add(newGame);
}
// Implementation of ActionListener interface.
public void actionPerformed(ActionEvent event)
{
boolean win = false;
guess = Integer.parseInt(guessText.getText());
if ( guess == numToGuess)
{
win = true;
}
else if ( guess < numToGuess)
{
winLbl.setText("Too Low");
guessPanel.setBackground(Color.red);
guess = Integer.parseInt(guessText.getText());
}
else if ( guess > numToGuess)
{
winLbl.setText("Too High");
guessPanel.setBackground(Color.blue);
guess = Integer.parseInt(guessText.getText());
}
winLbl.setText("Correct!");
guessPanel.setBackground(Color.green);
}
public static void main(String[] args)
{
GuessingGame game = new GuessingGame();
}
}
Your while-loop is inappropriate here, because you are in a actionPerformed() Method. This method is most likely to be called on a gui action (e.g. button kicked).
It should do one action corresponding to your needs and then terminate, since this method is invoked within the EDT. Your gui will not perform any updates until this method is finished.
Thus nothing will change (e.g. your win status) until the user makes some additional action, which he can't because your gui is frozen.
You don't update the value of guess. You'll need to read guess at the end of your loop, or at least in those cases that guess and numToGuess don't have the same value.
In the current case: if the values are not equal the first iteration, it will never become.
add
guess = Integer.parseInt(guessText.getText());
as last statement to each else if block
EDIT: a better way, as Marcinek points out, would be to remove the while loop, but since I don't know your requirements, I won't go as far as to claim it's the correct sollution.
Your loop keep runing because this condition if ( guess == numToGuess) never verfied
boolean win = false;
while (win == false){
if ( guess == numToGuess){
win = true;
}
.......
}
and
win still false, and while loop go a head runing.
while (win == false)
{
.....}

when shooting constantly repeats and goes faster every key stroke

Ok so i'm going to try to explain this, well I created a shoot method in a class that contains my bluespell, and all of it's constructors, well the problem is when I press space once it constantly shoots without me pressing it again, and if I press it twice the speed at which it fires doubles and it starts to contain more than one x and y position on my grid I just want the spell to fire when fired and I only need one item because I don't want there to be more than one instance of it on the grid I want it to be that the player cannot fire until the spell has left the grid, here's my code thanks oh and I only have it called in my key released seeing as it should only do it once the key has been released, but if that should change please let me know thanks :)
public void shootSpell(){
final BlueSpell b = new BlueSpell(GoodGuy.getx(), GoodGuy.gety() +1, BlueSpellWizard());
int delay = 100;
ActionListener taskPerformed = new ActionListener(){
public void actionPerformed(ActionEvent e){
if(b.gety() != 19){
WizardCells[b.getx()][b.gety()].setIcon(null);
WizardCells[b.getx()][b.changey(b.gety()+1)].setIcon(b.getIcon());
}
else{
WizardCells[b.getx()][b.gety()].setIcon(null);
b.changex(GoodGuy.getx());
b.changey(GoodGuy.gety() +1);
}
}
};
new Timer(delay, taskPerformed).start();
else if(key == KeyEvent.VK_SPACE){
GoodSpell.shootSpell();
}
Do not use a Timer! Your task should not repeat every 100 milliseconds. If I understand your code, you should run the code from your ActionListener in a new thread.
// Something like this,
new Thread(new Runnable() {
public void run() {
if (b.gety() != 19) {
WizardCells[b.getx()][b.gety()].setIcon(null);
WizardCells[b.getx()][b.changey(b.gety() + 1)].setIcon(b
.getIcon());
} else {
WizardCells[b.getx()][b.gety()].setIcon(null);
b.changex(GoodGuy.getx());
b.changey(GoodGuy.gety() + 1);
}
}
}).start();
You also need to do a check if the spell is currently in view/activate prior to initiating a new spell in the shoot() method...
public void shootSpell(){
//do a check here if a spell is already running!
final BlueSpell b = new BlueSpell(GoodGuy.getx(), GoodGuy.gety() +1, BlueSpellWizard());
int delay = 100;
//......
So in your method that is updating the spell going accross the screen you either need to have a flag in there if its still active, or if you are running it in a new thread, save that thread to a global var and check to see if the thread is running prior instantiating a new BlueSpell()

Making moving motion with labels using threads in java

I'm having a problem I'm making a pool game and I need the ballos to react when I simulate a hit, the program works like this, you click the direction and power to hit the ball and the click go, the go button is in the GUI class where my labels are created, the button calls a method from my main class that recieves the parameter and then with a while in it, changes the X and Y of the ball till the power is reduced to 0 and then stops, the code is working, but the ball moves until the while stops. So the while works and when the power int is 0 the while goes out and then the new X,Y are painted.
This is the funcion that the button calls, the button sends all the parameters
public void golpe(int pbola, int pvelocidad, String pdireccion, JLabel[] listalabels) throws InterruptedException{
listabolas[pbola].setVelocidad(pvelocidad);
listabolas[pbola].setDireccion(pdireccion);
while (listabolas[pbola].getVelocidad() > 0) {
moverBola(pbola, listalabels);
//System.out.println(listabolas[pbola].getPosX());
//System.out.println(listabolas[pbola].getPosY());
Thread.sleep(500);
//This line is supposed to change the X and Y of the object over and over
//but only does it till the end
listalabels[pbola].setLocation(listabolas[pbola].getPosX(), listabolas[pbola].getPosY());
}
}
Here is the function moverbola(), only copied one "if" so that the code doesn't look to big
private void moverBola(int pbola, JLabel[] listalabels) {
if (listabolas[pbola].getDireccion().equals("SE")) {
int pposX = listabolas[pbola].getPosX();
listabolas[pbola].setPosX(pposX + 1);
int pposY = listabolas[pbola].getPosY();
listabolas[pbola].setPosY(pposY + 1);
}
Swing is a single threaded framework. That is, all interactions with UI are expected to occur from within a single thread, known as the Event Dispatching Thread.
Any action that blocks this thread, will prevent the EDT from updating the screen or processing any new events.
Your while-loop is blocking the EDT, preventing it from painting any updates until after the while-loop is completed.
Take a look at Concurrency in Swing for more details.
There are a number of approaches you could take...
You could use a Thread, but this causes problems as you need to ensure that any changes you make to the UI are re-synced back to the EDT and this can become messy...
For example
You could use a javax.swing.Timer that ticks at a regular interval and you would update any internal parameters from within it's assigned ActionListener. Because the tick events occur within the EDT, it is save to update the screen from within it.
For example
You could use a SwingWorker to run the task in the background. It has methods for re-syncing updates back to the EDT, but might be a little over kill for your purposes...
Updated with a possible Timer example
Caveat- It is very hard to produce a reasonable example with only a code snippet, but, something like this might work
public void golpe(final int pbola, int pvelocidad, String pdireccion, final JLabel[] listalabels) throws InterruptedException{
listabolas[pbola].setVelocidad(pvelocidad);
listabolas[pbola].setDireccion(pdireccion);
Timer timer = new Timer(40, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (listabolas[pbola].getVelocidad() == 0) {
((Timer)evt.getSource()).stop();
} else {
moverBola(pbola, listalabels);
}
}
});
timer.setRepeats(true);
timer.start();
}

Properly implementing a delay in a game

This is a follow up to a previous question I had. I have a Battleships game with two boards. When the user clicks on the computer board an action occurs, along these lines:
public void mouseClicked(MouseEvent e)
// Get coordinates of mouse click
if (//Set contains cell) {
/add Cell to set of attacked cells
//Determine if set contains attacked cell.
// If yes, hit, if no, miss.
checkForWinner();
The checkForWinner method determines if the game has been won yet. If it hasn't it calls a nextTurn method which changes the current turn. If the currentTurn is set to Computer, a ComputerMove() method is automatically called.
When that method finishes, it again checksforWinner, changes turn and waits for the user to click on the grid to start the cycle again.
Ideally, I'd like to have sound effects, or at the very least a pause between moves. However, no matter how I use Thread.sleep, or TimerTask, or anything else, I can't get it to function correctly.
If I use a simple Thread.sleep(500) in the CheckforWinner method, or in the ComputerMove method, all that happens is the human's go is delayed for the set amount of time. As soon as his move is executed the computer's move is completed immediately.
I know very little about threads but I assume this is because all the initiation of the bouncing back and forth between methods begins with a method in the mouse listener.
Given the set up of my system, is there a way to implement a delay without radically changing things?
Edit: May as well include the classes:
public void checkForWinner() {
if (human.isDefeated())
JOptionPane.showMessageDialog(null, computer.getName() + " wins!");
else if (computer.isDefeated())
JOptionPane.showMessageDialog(null, human.getName() + " wins!");
else
nextTurn();
}
public void nextTurn() {
if (currentTurn == computer) {
currentTurn = human;
} else {
currentTurn = computer;
computerMove();
}
}
public void computerMove() {
if (UI.currentDifficulty == battleships.UI.difficulty.EASY)
computerEasyMove();
else
computerHardMove();
}
public void computerEasyMove() {
// Bunch of code to pick a square and determine if its a hit or not.
checkForWinner();
}
Ideally, I'd like to have sound effects, or at the very least a pause between moves. However, no matter how I use Thread.sleep, or TimerTask, or anything else, I can't get it to function correctly.
You should be using a Swing Timer. Something like:
Timer timer = new Timer(1000, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
currentTurn = computer;
computerMove();
}
});
timer.setRepeats(false);
timer.start();

How can I solve delay in showing count down timer(JLabel) in Swing JPanel

I've implemented a count down timer(in function) which updates a label in swing panel every second this is the code:
public void DefineTimer()
{
Action updateClockAction = new AbstractAction() {
public void actionPerformed(ActionEvent e){
JPanelMainGame.this.jLabelSeconds.setText(Integer.toString(JPanelMainGame.this.m_TimerTotalSeconds));
JPanelMainGame.this.jLabelSeconds.setFont(new java.awt.Font("Lucida Handwriting", 1, 36));
JPanelMainGame.this.jLabelSeconds.setForeground(Color.red);
JPanelMainGame.this.jLabelSeconds.setVisible(true);
if( JPanelMainGame.this.m_TimerTotalSeconds >0)
{
JPanelMainGame.this.m_TimerTotalSeconds--;
}
else if ( JPanelMainGame.this.m_TimerTotalSeconds == 0)
{
JPanelMainGame.this.m_Timer.stop();
JPanelMainGame.this.jLabelSeconds.setText("0");
System.out.println("!m_WasGameDecisived: "+!m_WasGameDecisived);
JPanelGameApplet gameApplet = (JPanelGameApplet) getTopLevelAncestor();
//Checking whether time ended for both players and no solution was recieved
if(gameApplet.GetJPanelChooseGame().GetGameType() == eGameType.Net)
{
gameApplet.GetClinetThread().UpdateServerOfTimeEnded();
if (!m_WasGameDecisived)
{
//
System.out.println("Tie - No one had a solution in the given time");
System.out.println("Before send request to solve - Is Socket Closed:"+((JPanelGameApplet)
gameApplet.GetClinetThread().SendRequestToClosePlayerThreadAndRemoveItFromPlayersOnServer();
((JPanelGameApplet)getTopLevelAncestor()).GetDJ().stop();
Menu.BrowseTo(PanelMenuNumber.k_ChooseGame, JPanelMainGame.this.getParent());
((JPanelGameApplet)getTopLevelAncestor()).GetDJ().play(0);
}
}
else if(gameApplet.GetJPanelChooseGame().GetGameType() == eGameType.Single)
{
JPanelMainGame.this.showPopUpSelectionBar();
}
}
((JPanelGameApplet)getTopLevelAncestor()).GetNetMainGame().Initialize();
}
};
m_Timer = new Timer(1000, updateClockAction);
}
Now my problem is in another part of my code when I want to to the following things:
case ProtocolMessages.k_StartGame:
m_GameApplet.GetJpanelStartNetGame().DefineTimer();
m_GameApplet.GetJpanelStartNetGame().GetTimer().start();
m_GameApplet.ShowBoardToSolve();
Menu.BrowseTo(PanelMenuNumber.k_NetPlayersGameStart,m_GameApplet.GetJPanelNetGameSetting().getParent());
m_GameApplet.GetDJ().Next();
break;
So The problem is when I want to start a game, I'm defining my timer and allocating it,
give it start command and going to the screen that I should see there the timer (JLabel updating).
And still although it should be already counting (even before that screen that shows the timer) I still got delay: I get the panel that show the timer, and after about two seconds the Jlabel appear and start to count down.
I think that it is because the event dispatch thread that is not updating immediately the Jlabel in the time I'm doing Jlabel.setText()
Any suggestions of how can I start a game without delay in showing the Jlabel?
Thanks
Call SwingUtilities.invokeAndWait frm the thread to set the label text.

Categories