I'm trying to write a logic in memory game that when I click on cards and they are not a pair (different ID), program should swap them back after 1s. If they are same, then leave them as they are.
The problem is that when I first click and the card appears, after second clicking on another (different) card it doesn't appear and swap the first card after 1s. someone knows why the second card does not appear after clicking?
Btw when the pair is correct, everything works fine, here is my fragment of the code responsible for that logic in listener:
final int copy = i;
card2.addActionListener((e) -> {
card2.setIcon(new ImageIcon(icons[copy].getAbsolutePath()));
if(firstClick == null)
{
firstClick = (Card)e.getSource();
}
else
{
Card secondClick = (Card)e.getSource();
if(firstClick.getID() != secondClick.getID())
{
try
{
Thread.sleep(1000);
} catch (InterruptedException e1)
{
//e1.printStackTrace();
}
firstClick.setIcon(new ImageIcon(background.getAbsolutePath()));
secondClick.setIcon(new ImageIcon(background.getAbsolutePath()));
firstClick = null;
}
else
firstClick = null;
}
});
While method actionPerformed is executing, the GUI cannot react to mouse and keyboard events, so basically your code is "freezing" your GUI for one second. I believe that the class javax.swing.Timer is what you need and at first glance it looks like the duplicate question that MadProgrammer referred to may help you.
Related
I am writing a board game where I need to check for enemies on the the player is moving and prompt to make an attack. However because of how the game is made the move method is called on the JavaFX application thread, I want to be able to prompt the user if they want to fight an enemy.
My dialogue box which works fine normal uses wait and notify which dont work on the main thread without crashing the program, does anyone know how to pause the execution of this thread until a user clicks one of the buttons.
I apologise for the description, its late.
Method that checks for enemies
This method checks for the enemies and returns the enemy if the user selected yes. It runs on the JavaFX Thread.
private Ship pathBattle(Vector gridPosition){
//Check if there are ships on the path to the destination
for(Button cell : activeButtons){
//Check the button position is not that of the current button, dont go past the current button
Vector pixPosition = new Vector(cell.getLayoutX(), cell.getLayoutY());
//Convert to a grid referance
Vector gridPos = Vector.pixToGrid(pixPosition);
if(!gridPos.equals(gridPosition)){
//This button is not the destination
//Check for any ships on that cell
Ship collided = Ship.isOccupiedButton(cell);//Returns the ship if there is one on the cell
if(collided != null){
//There is a ship, prompt to battle
boolean battle = UtilPopups.showConfirmationDialog("Do you want to battle " + collided.getName(), "YAR!", "NAY!");
Game.printError("Ship collision");
if(battle){
return collided; //Return the ship to battle
}
}
}
//On to the next button
}
return null;
}
The code to display the Popup
This does work in other areas of the porgram with no issue
public static boolean showConfirmationDialog(String lblPrompt, String btnYes, String btnNo){
//Check if the confirmation controller is not null
if(confirmationDialog != null){
confirmationDialog.lbl_prompt.setText(lblPrompt);
confirmationDialog.btn_no.setText(btnNo);
confirmationDialog.btn_yes.setText(btnYes);
//Show the base
show(confirmationDialog.base_pane);
//Pause this thread until user input is given from GUI thread
synchronized (confirmationDialog) {
try{
confirmationDialog.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
//Program resumed, user input given and stored in response
if(confirmationDialog.response.equals("yes")){
confirmationDialog.response = null; //Set back to null
return true;
} else {
confirmationDialog.response = null; //Set back to null
return false;
}
}
//Class not initialized
Game.printError("UtilPopups->showConfirmationDialog: Dialog NULL!");
return false;
}
For blocking any caller thread during showing dialog, for example:
static private void showAndBlock(Dialog dialog) {
if (Platform.isFxApplicationThread()) {
dialog.showAndWait();
} else {
CountDownLatch lock = new CountDownLatch(1);
Platform.runLater(() -> {
dialog.showAndWait();
lock.countDown();
});
try {
lock.await();
} catch (InterruptedException e) {
// Just in case you call yourTherad.interrupt(),
// the thread will be joined forcibly through here.
}
}
}
But I'm not sure whether or not it works in your threading design.
The collided method literally doesnt nothing, it doesn't ask for a input so it can't work.
I think, sorry not good english
I have a problem that probably has a simple fix but I can't seem to get it to work.
I need my program to pause or wait until the user selects either the skip button, or the positive/negative feedback button, before moving on.
I assume this is going to require basic threading, but I'm not sure how to implement it. Any help will be appreacited.
The gui is displayed in a separate class(GUI) and the rest is another class.
The code is sort of messy as it was coded for a Hackfest in 12 hours.
EDIT: Solved it on my own by removing button listeneers and making the variables static.
public void onStatus(Status status) {
//this is a listener from the Twitter4J class. Every time new Tweet comes in it updates.
for (int i = 0; i <= posWords.length; i++) {
if (status.getText().toLowerCase().contains(gui.sCrit.getText())
&& (status.getText().toLowerCase().contains(posWords[i].toLowerCase()))) {
//If the tweet matches this criteria do the following:
String tweet;
Status tempStoreP;
System.out.println("Flagged positive because of " +posWords[i].toLowerCase()+" " + i);
tempStoreP = status;
tweet = tempStoreP.getUser().getName() + ":" + tempStoreP.getText() + " | Flagged as positive \n\r";
gui.cTweet.setText(tweet);
//Write to log
try {
wPLog.append("~" + tweet);
} catch (IOException e) {
}
//Add action listeneer to gTweet.
//here is my problem. I want it to wait until a user has clicked one of these buttons before moving on and getting the next Tweet. It has to pause the thread until a button is clicked then it can only move on to getting another Tweet.
//the problem is that the button listener uses local variables to work.
gui.gTweet.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (gui.pTweet.getText().equalsIgnoreCase("")) {
gui.pTweet.setText("Please type a response");
} else if (gui.pTweet.getText().equalsIgnoreCase("Please type a response")) {
gui.pTweet.setText("Please type a response");
} else {
try {
Status sendPTweet = twitter
.updateStatus("#" + tempStoreP.getUser().getScreenName() + " "
+ gui.pTweet.getText());
} catch (TwitterException e1) {
}
}
gui.gTweet.removeActionListener(this);
}
});
//add Aaction listert to sTweet
gui.sTweet.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
wPLog.append("Skipped \n\r");
} catch (IOException e1) {
}
gui.sTweet.removeActionListener(this);
}
});
}
Thank you for any help. On a side note, if anyone can tell me why when the button is clicked, it loops and spams people with the same message, it will be helpful. Thank you.
I thought about the multithreading thing and i think it isn't easy enough.
If i were you i would disable all controls except the button that is to click.
Example:
JButton button = new JButton( "Test );
button.setEnabled( false );
The user won't be able to click the button until you use button.setEnabled( true );, if you just disable all controls but the button that should be fine.
In my understand of your problem you can use Multithreading like this:
try{
while(!isSkipClicked){
//your multithreading code
}
//code to move...
}
or
you can use dispose method if you have 2 JFrame.
or
you can use multiple JPanel like while skip button clicked hide pnl1 and show pnl2 using method
pnl1.setvisible(false);
pbl2.setVisible(true);
I assume this is going to require basic threading,
Not true at all.
You say you want your program to "wait." That word doesn't actually mean much to a Swing application. A Swing application is event driven. That is to say, your program mostly consists of event handlers that are called by Swing's top-level loop (a.k.a., the Event Dispatch Thread or EDT) in response to various things happening such as mouse clicks, keyboard events, timers, ...
In an event driven program, "Wait until X" mostly means to disable something, and then re-enable it in the X handler.
Of course, Swing programs sometimes create other threads to handle input from sources that the GUI framework does not know about and, to perform "background" calculations. In that case, "Wait until X" might mean to signal some thread to pause, and then signal it to continue its work in the X handler.
I wrote a complex java program, that has a GUI.
In the GUI I have three buttons, "play", "play all" and "reset", and some table.
When I click play, the program does its logic and then prints the output to the table i mentioned. this is working fine, as intended. after a certain amount of "play" operations, we printed all the data to the table and so we are done and can no longer click it. at the point, i disable the play button.
When I click play all, I want it to be as if I clicked "play" until it is no longer possible. So I wrote this code:
public synchronized void actionPerformed(ActionEvent event)
{
if(event.getSource() == playAllButton)
{
while(playButton.isEnabled())
{
playButton.doClick();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
if(event.getSource() == playButton)
{
Command command = listOfCommands.get(commandNumber++);
if(command.getCommandType() == "PF")
{
PFLabel.setText("PF Count:" + (++PFCount));
}
if(command.getCommandType() == "PR")
{
PRLabel.setText("PR Count:" + (++PRCount));
}
if(command.getCommandType() == "GP")
{
if(checkIfPF())
{
addPageToRam(((GPCommand)command).getPage());
}
else
{
if(checkIfPR(((GPCommand)command).getPage().getPageId()))
{
replacePage(((GPCommand)command).getPage(),getWithWhoToReplace(((GPCommand)command).getPage().getPageId()));
}
}
}
}
if(commandNumber == listOfCommands.size()) // we are done!
{
playButton.setEnabled(false);
}
}
As I mentioned, when I click the play button, it immediately prints the result as intended.
But when I click play all, it runs for a very long time without displaying any output, and then at the end prints just the final result. This isn't what I want. What I want is for it to print the current result, wait a bit so I can look at it, and then print the next result.
Even when I remove the Thread.sleep it is very slow (and still only prints the last result).
Is there a way to make it run faster? And more importantly - how do I make it wait before clicking the button again? I want to view the current result for a while before it clicks again.
In the comments section I figured out, that the issue could be solved by using SwingWorkers and moving the long-time-performing code to an asynchronous task. Mr. Coobird has posted a way, how to do this here.
Hi I'm new to stackoverflow so bear with me if I make mistakes.
I'm making this Java Simon Says Game for a class project. It works by a random number generator for each sequence#. I show the sequence through doClick() but remove the actionlisteners beforehand and add it afterwards.
The problem is the buttons won't unpress or unarm until all other buttons have been pressed. I've tried using thread.sleep to put a delay between each if...else statements yet it only stays pressed for longer. I've tried updating the gui through repaint(), revalidate(), updateUI() within the try... catch of the thread.sleep but that didn't work either.
I've realized this issue is mainly cosmetic because when I tried implementing setPressed or setArmed it said it wasn't being pressed but it looked pressed.
Here is the code snippet in it's most simplest form without thread.sleep or my previous attempts in comments.
public void sequence2() //This is where the issue happens. The buttons won't unpress until every button has been pressed.
{
level.setText(" Level 2"); //Level indicator
Green.removeActionListener(Listener);
Red.removeActionListener(Listener);
Yellow.removeActionListener(Listener);
Blue.removeActionListener(Listener);
if(sequence1 == 1)
{
Green.doClick(300); //Programmatically clicks the button
}
else if(sequence1 == 2)
{
Red.doClick(300);
}
else if(sequence1 == 3)
{
Yellow.doClick(300);
}
else if(sequence1 == 4)
{
Blue.doClick(300);
}
if(sequence2 == 1)
{
Green.doClick(300);
}
else if(sequence2 == 2)
{
Red.doClick(300);
}
else if(sequence2 == 3)
{
Yellow.doClick(300);
}
else if(sequence2 == 4)
{
Blue.doClick(300);
}
Green.addActionListener(Listener);
Red.addActionListener(Listener);
Yellow.addActionListener(Listener);
Blue.addActionListener(Listener);
}
I'm very new to java so I'm not skilled in multithreading or working on the Event Dispatch Thread for that manner. But if that's the only solution I'll need some more help with that.
I have the full code in a zip file with previous attempts commented out if that will help.
https://drive.google.com/file/d/0Bxg4WleC9jD2VFhoZmZBNjV6Vkk/view?usp=sharing
Invoking doClick() may be an awkward choice for this, as it uses a Timer internally. Instead, use a JToggleButton, which will allow you to control each button's appearance based on its selected state using setSelected(). A complete example is shown in the game Buttons. In the ActionListener of your Swing Timer, select the current button, play its note and increment the sequence index. When all notes have been played, unselect all the buttons.
Addendum: Can you show how you implement the timer?
In outline, given a suitable list of toggle buttons:
private static final int MAX = 4;
List<JToggleButton> buttons = new ArrayList<JToggleButton>(MAX);
private int i;
The timer's listener might look like this:
#Override
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
JToggleButton b = buttons.get(i);
if (i > MAX) { // reset i and all the buttons
for (JToggleButton b : buttons) {
b.setSelected(false);
}
timer.stop();
i = 0;
} else {
b.setSelected(true);
// play tone i
i++;
}
}
A toggle button's item listener should update the button's appearance as indicated by its state:
#Override
public void itemStateChanged(ItemEvent e) {
JToggleButton b = (JToggleButton) e.getItem();
if (b.isSelected()) {
// change icon, color etc.
} else {
// restore icon, color etc.
}
}
i have a problem with my code. I think that my problem is easy,but i have compiled for 3 days without good results. I have three images. They are put on screen one-one each time. User choose from 4 button if image's side is up, down, right or left. Also, i want to understand if user was wrong and then i will count errors. When user make 3 errors then the game will stop. I have shown code below. Please help me if you have any good idea.
The problem is that at the first loop,run right.It goes at the first if. After that it do the loop and then it does not go to second if.
if it is more helpful,some details:
i want to make a programma that it will show to user an image.This image has 4 sides (up,down,right,left).When the image is at "up side",user has to click on up button,when the image is at "down side",user has to click on down button etc. User can do 3 errors max. At first,program show the image at right side,if user clicks on right button then i want to show the "second image" at left side.If user does not at left side,then i want to add an error(error++) and after it shows the third image at up side etc. I hope it is more helpful to understand. If you can't please let me know.
My program is at Netbeans,java.
Thank you
public void actionPerformed(ActionEvent e)
{
while(errors<3)
{
image.setIcon(createImageIcon("visual1" + e.getActionCommand() + ".PNG"));
if (k==1)
{
if(e.getSource() == right_button)
{
image.setIcon(createImageIcon("visual2" + e.getActionCommand() + ".PNG"));
}
}
else if ( k==2 )
{
if(e.getSource() == left_button )
{
image.setIcon(createImageIcon("visual3" + e.getActionCommand() + ".PNG"));
}
}
else if (k==3 )
{
if(e.getSource() == up_button)
{
System.out.print("if3");
}
}
else
{
errors++;
}
k=k+1;
}
}
You should consider calling Repaint and Invalidate, right after you update your GUI like this -
mainframe.repaint();
mainframe.invalidate();
here mainframe is your JFrame object.
A problem I see with your while loop is that it is at risk of getting stuck in an infinite loop, since the variable used as an exit criterion is only updated some of the time, in an else block. I think you should re-arrange your logic:
Get rid of that while loop as it will only cause trouble. It is useful for a linear command line program but not for an event-driven GUI program like yours.
Read in all images and create all ImageIcons in the class constructor, and store them in variables. There's no need to re-read the images multiple times (unless they're huge).
Instead of using a while loop, increment the error variable in your method above, and then write the method so that it will change behaviors depending on the value of error (depending on the state of the class).
e.g.,
// somewhere in your code create your icons
Icon rightIcon = ......;
Icon leftIcon = .....;
Icon upIcon = .....;
Icon downIcon = .....;
// elsewhere in your code
public void actionPerformed(ActionEvent e) {
if (errors >= 3) {
// notify user of error
return; // end this method
}
// check if current icon matches image
// if so, change icon
// if not increment error
}
Note that an enum Direction {UP, DOWN, LEFT, RIGHT} and a Map<Direction, Icon> could be helpful here.