Syntax error, insert "{" to complete EnumBody (at end of class) - java

package checkers;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JPanel;
enum Job{SPAWN, KING, NORM};
enum myColor{RED, BLACK};
int tileRow;
int tileCol;
Job job;
myColor side;
JButton button;
Checker piece;
Color color;
public class Tile
{
public Tile(int posRow, int posCol, JPanel panel, ActionListener listener)
{
int tileRow = posRow;
int tileCol = posCol;
if(tileRow > 9 || tileRow < 1)
job = Job.KING;
else if(tileRow < 4 || tileRow > 6)
job = Job.SPAWN;
else
job = Job.NORM;
button = new JButton();
button.setPreferredSize(new Dimension(83, 83));
if(tileRow%2==0)
{
if(tileCol%2==0)
{
color = Color.BLACK;
}
else
color = Color.RED;
}
else
{
if(tileCol%2!=0)
{
color = Color.BLACK;
}
else
color = Color.RED;
}
button.addActionListener((java.awt.event.ActionListener) listener);
}
public void Reset()
{
}
public boolean isClicked(Object source)
{
if(source == button)
return true;
else
return false;
}
}
EDIT I edited in the entirety of my code body. The myColor closing brace is, as far as Eclipse knows, 'supposed' to be after the classBody.
Eclipse wants me to remove myColor's closing brace, and replace it with a semi-colon; regardless of whether or not I place the semi-colon, Eclipse tells me that the closing brace is not supposed to be there, and if I remove it, reads my classBody closing brace as being the EnumBody closing brace.
I dunno what the hell is going on, but it's definitely causing weird things to happen within the class (making a Tile class+object for a game of checkers).
And by weird things, I mean I can't make an array of Tile objects from another class if I want Eclipse to read Tile as having no errors.

Not exactly sure the error message you are getting. Below example EnumIssue.java works fine:
public class EnumIssue {
enum Job
{
SPAWN, KING, NORM
}
enum myColor
{
RED, BLACK
}
public static void main(String[] args) {
Job j = Job.SPAWN;
myColor c = myColor.BLACK;
System.out.println(j);
System.out.println(c);
}
}
Output:
SPAWN
BLACK
Added after entire code was provided in question:
Move the variable declarations in the class Tile. The updated snippet is below:
:
:
import javax.swing.JPanel;
enum Job{SPAWN, KING, NORM};
enum myColor{RED, BLACK};
//This is where current variable declarations are. Move them inside class.
public class Tile
{
//This is where variable declarations are moved to.
int tileRow;
int tileCol;
Job job;
myColor side;
JButton button;
Checker piece;
Color color;
public Tile(int posRow, int posCol, JPanel panel, ActionListener listener)
{
int tileRow = posRow;
:
:

Related

Java Timer and drawing animations

I have no idea how to fix this problem. What I am doing is trying to break up a monster class I have into different things, like one class for player, one for fireball, etc. I had everything working before I tried to break up the class but now I am getting an error. I was wondering if anyone could help me solve it and explain to me how not to repeat this error again. Thank you in advance.
EDIT: The error is on: animationTimer = new Timer(animationDelay, this);
EDIT:1 error found:
File: C:\Users\jozef\Java\Dragon Ball Z\Player.java [line: 45]
Error: incompatible types: Player cannot be converted to java.awt.event.ActionListener
Also, I do format properly but when i try to copy and paste my code into the box to post here it doesn't count it as code so i have to indent every line to get it to appear as code and no normal text.
import java.awt.Graphics;
import java.awt.MediaTracker;
import javax.swing.ImageIcon;
import java.awt.Image;
import java.awt.event.ActionEvent;
import javax.swing.Timer;
public class Player {
int x;
int y;
ImageIcon pictures[];
int total;
int current;
boolean sideMove;
int move;
Timer animationTimer;
int animationDelay = 80;
public Player(int startX, int startY, ImageIcon image[], boolean sideMove, int move) {
x = startX;
y = startY;
pictures = image;
total = pictures.length;
this.sideMove = sideMove;
this.move = move;
startAnimation();
}
public void draw(Graphics g) {
if (pictures[current].getImageLoadStatus() == MediaTracker.COMPLETE) {
Image img = pictures[current].getImage();
g.drawImage(img, x, y, null);
current = (current + 1) % total;
}
update();
}
public void update() {
if (sideMove == true) {
x += move;
} else {
y += move;
}
}
public void startAnimation() {
if (animationTimer == null) {
current = 0;
animationTimer = new Timer(animationDelay, this); // *** error ***
animationTimer.start();
} else if (!animationTimer.isRunning())
animationTimer.restart();
}
public void stopAnimation() {
animationTimer.stop();
}
}
Here:
animationTimer = new Timer(animationDelay, this);
Since the Player class does not implement ActionListener this can not be passed in to the Timer constructor as a valid parameter. A possible solution is to have your Player class implement ActionListener giving it an appropriate actionPerformed method:
public class Player implements ActionListener {
#Override
protected void actionPerformed(ActionEvent e) {
// your coded here
}
// .... rest of your code
or better still, use a different ActionListener such as an anonymous inner class.
e.g.,
public void startAnimation() {
if (animationTimer == null) {
current = 0;
animationTimer = new Timer(animationDelay, e -> timerActionPerformed(e));
animationTimer.start();
} else if (!animationTimer.isRunning()) {
animationTimer.restart();
}
}
private void timerActionPerformed(ActionEvent e) {
// TODO repeated code goes here
}
Side recommendations:
You've got code within your painting method that changes your Player object's state, something that you'll want to avoid. Understand that you can only partially control when or even if an object will be painted, and so it would be best to keep these separate.
Myself, I'd get the Timer out of the Player class and instead use a Timer as your game loop or animation controller in a more general overall control class, perhaps the Game class (or whatever your "universe" class is called), the class that holds and controls all of your logical entities such as your Player objects.
This is the signature of javax.swing.Timer constructor:
public Timer(int delay, ActionListener listener)
You are providing an int and a Player..
You should create an ActionListener as well and provide it to the constructor or you could pass this but Player class should implements ActionListener inteface (you should write actionPerformed method in the Player class).
Read more info about Timer Here (official java doc).

JavaFX : Button never sets a graphic

EDIT :
A MCVE version of my code has been made to help debug it. It reproduces my bug. The purpose of my code is doing a Memory game. Which means that when it is your turn, you "open" a card, then another one. If they form a pair, they don't get turned over, they stay open. Otherwise, you turn them back over and try to find a pair on the next turn.
Simply put, the bug is : when you are opening the second card of your turn and both cards don't form a pair, the second one never gets opened!
Hopefully, this version of my code will help you to find the bug, which will help me a lot!
I have put the code on Github : https://gist.github.com/anonymous/e866671d80384ae53b53
(And you will find it attached at the end of the question)
Explanation of the issue
I am having fun on doing a little Memory game in JavaFX and I came across this strange behavior where the card I click on (represented by a custom class that extends the Button class) never changes the image displayed.
Normally, when I click on the card, it "opens" itself by changing the graphic it displays.
The strange and annoying thing is that it only happens in a specific case.
The behavior of my card is correct when I "open" the first card of the turn of the player. It also works when I "open" a second one and both cards are a pair. Sadly, it doesn't work only in the case where I want to open a second card and it doesn't match as a pair with the first one.
I modified the Button class by adding openCard() and closeCard() methods. Those methods will set a specific graphic on the button-card.
I will now show some code but it is hard to tell what might be the part that is making this behavior happen. Even more so that I am using Eclipse but can't possibly figure out how to debug a JavaFX app with breakpoints (I am using console prints) because the app will eventually crash when I reach my breakpoints and start crawling through the lines of code.
The code
Firstly, the modified Button class :
public class Card extends Button{
private String cardDesign;
public Card(int row, int column){
this.setGraphic(new ImageView("/resources/card_back.png"));
this.setBackground(new Background(new BackgroundFill(Color.SLATEGRAY,
new CornerRadii(6), null)));
}
public void setOpenCardDesign(String design){ cardDesign = design; }
public void openCard(){ this.setGraphic(new ImageView(cardDesign)); }
public void closeCard(){
this.setGraphic(new ImageView("/resources/card_back.png"));
}
}
Now the controller class, the event is set on a MouseEvent. There is more code in this controller (like checking if there is a pair), but this isn't an issue here I think as the problem is already at the line where I call the method to open the card.
I use the getSource() method here because my cards are arranged in a gridPane and I need to know which one has been clicked on.
#Override
public void handle(MouseEvent event) {
//Get the card that was clicked on
Card card = (Card) event.getSource();
//Open the card
card.openCard();
//Do some more after this...
}
That's pretty much it as from what I could figure out.
As already stated, I tried to check if the method openCard() is being called. It is as some comment printed in my console showed up. I even added some console printing just before and just after the line where I set the graphic and they both are showing up. I can't know for sure what happens when my app reaches the setGraphic() line as nothing is showing up in my app (the card remains closed).
Any hint would help because I am slowly sinking in madness right now.
Thank you in advance.
The MCVE version of my code
The card object : Card.java
package memory;
import javafx.scene.control.Button;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.paint.Color;
public class Card extends Button{
//-------------------------------------------------
//Store the position of the card
private int row;
private int column;
//-------------------------------------------------
//Constructor
public Card(int row, int column){
//Give the cards a specific color at init
this.setBackground(new Background(new BackgroundFill(Color.DEEPSKYBLUE,
new CornerRadii(6), null)));
this.setText("CLOSED");
this.row = row;
this.column = column;
}
//-------------------------------------------------
//Open the card
public void openCard(){
System.out.println("OPEN");
//Cards are red when open
this.setBackground(new Background(new BackgroundFill(Color.RED,
new CornerRadii(6), null)));
this.setText("OPEN");
}
//-------------------------------------------------
//Close the card
public void closeCard(){
System.out.println("CLOSE");
//Cards are blue when closed
this.setBackground(new Background(new BackgroundFill(Color.DEEPSKYBLUE,
new CornerRadii(6), null)));
this.setText("CLOSED");
}
//-------------------------------------------------
//Getters for row and column info
public int getRow() { return row; }
public int getColumn() { return column; }
}
The main (includes the view and start point of the app) : Main.java
package memory;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Main extends Application {
//-------------------------------------------------
//The layout and the cards
GridPane gridCard = new GridPane();
static Card [][] cardArray;
//The event handler
private static EventHandler<MouseEvent> handler;
//The array which remembers the pairs and the reminder of last open card
static int[][] indexArray;
static int index;
//Boolean array to check if the card is already open
static boolean[][] isOpen;
//Number of pairs to find
static int pairs = 5;
//-------------------------------------------------
//Cheap main
public static void main(String[] args) {
Application.launch(args);
}
//-------------------------------------------------
#Override
public void start(Stage primaryStage) throws Exception {
//Init the event handler
handler = new Controller();
//Some formatting for the grid pane
gridCard.setHgap(10);
gridCard.setVgap(10);
gridCard.setPadding(new Insets(0, 10, 0, 10));
gridCard.setAlignment(Pos.CENTER);
//Creating our card board, index array and bool array
cardArray = new Card [2][5];
indexArray = new int [2][5];
isOpen = new boolean [2][5];
//Adding the cards to our card array
for(int i = 0; i < 2; i++){
for(int j = 0; j < 5; j++){
cardArray[i][j] = new Card(i, j);
//Make those buttons look like cards
cardArray[i][j].setPrefHeight(100);
cardArray[i][j].setPrefWidth(70);
//Register the event
cardArray[i][j].addEventHandler(MouseEvent.MOUSE_CLICKED, gameController());
//Add those cards
gridCard.add(cardArray[i][j], j, i);
//Set the pairs (no randomness here)
indexArray[i][j] = j+1;
}
}
//Print out the indexes of all the cards
System.out.println("----------------");
System.out.println("Card indexes :");
for (int i = 0; i < indexArray.length; i++) {
System.out.println();
for (int j = 0; j < indexArray[0].length; j++) {
System.out.print(indexArray[i][j]+ " | ");
}
System.out.println();
}
System.out.println("----------------");
//Set BorderPane
BorderPane root = new BorderPane();
root.setBackground(new Background(new BackgroundFill(Color.BLACK,
CornerRadii.EMPTY, null)));
root.setCenter(gridCard);
//Set the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Memory Test");
primaryStage.show();
}
//-------------------------------------------------
//Getter for the event handler
public static EventHandler<MouseEvent> gameController() {
return handler;
}
//-------------------------------------------------
//Getter, Setter and "resetter" for the index
public static void resetIndex() { index = 0; }
public static int getIndex() { return index; }
public static void setIndex(int i) {
index = i;
}
//-------------------------------------------------
}
The controller : Controller.java
package memory;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.input.MouseEvent;
public class Controller implements EventHandler<MouseEvent>{
//-------------------------------------------------
#Override
public void handle(MouseEvent event) {
//Get the card which cas clicked on
Card card = (Card) event.getSource();
//If the card was already open, don't do anything
if (!Main.isOpen[card.getRow()][card.getColumn()]) {
//Open the card
card.openCard();
//We opened the first card of the turn
if (Main.getIndex() == 0) {
//Set the card as open
Main.isOpen[card.getRow()][card.getColumn()] = true;
//Remember the index
Main.setIndex(Main.indexArray[card.getRow()][card.getColumn()]);
System.out.println("index: "+Main.getIndex());
//We opened the second card
}else if (Main.getIndex() != 0) {
//Check if it is a pair
if (Main.getIndex() == Main.indexArray[card.getRow()][card.getColumn()]) {
//Decrement the number of pairs
Main.pairs--;
//Open the second card
Main.isOpen[card.getRow()][card.getColumn()] = true;
//Reset the index
Main.resetIndex();
}else{ //Close both cards if it isn't a pair
//Wait 0.7 second to let the player remember the cards
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Close the current card
card.closeCard();
System.out.println("index : " + Main.indexArray[card.getRow()][card.getColumn()]);
Main.isOpen[card.getRow()][card.getColumn()] = false;
//Close the first opened card by looking at the index
//It closes both cards with the same index, but it doesn't matter
//as the pair hasn't been found anyway
for (int i = 0; i < Main.indexArray.length; i++) {
for (int j = 0; j < Main.indexArray[0].length; j++) {
if (Main.getIndex() == Main.indexArray[i][j]) {
Main.cardArray[i][j].closeCard();
System.out.println("index: " + Main.indexArray[i][j]);
Main.isOpen[i][j] = false;
}
}
}
//Reset the index of last opened card
Main.resetIndex();
}
}
}
//Check endgame
if (Main.pairs == 0) {
//Show a dialog box
Alert incorrectPairs = new Alert(AlertType.INFORMATION);
incorrectPairs.setTitle("GAME OVER");
incorrectPairs.setHeaderText("The game is over");
incorrectPairs.setContentText("You found all the pairs, congrats!");
incorrectPairs.showAndWait();
}
}
//-------------------------------------------------
}
You're blocking the UI thread with Thread.sleep(...). That prevents any pending changes from being repainted, so you don't see the first update at all; you only see the subsequent updates after the pause is complete.
The simplest way to implement a pause on the UI thread is to use a PauseTransition from the JavaFX animation API. Basically, you do
PauseTransition pause = new PauseTransition(Duration.millis(700));
pause.setOnFinished(e -> {
// code to execute after pause...
});
pause.play();
In your case, you probably want to disable the user interface, so the user cannot click on anything during the pause, so you could do something like
PauseTransition pause = new PauseTransition(Duration.millis(700));
pause.setOnFinished(e -> {
card.closeCard();
// ... etc...
card.getParent().setDisable(false);
});
card.getParent().setDisable(true);
pause.play();

Adding text to JTextArea from another class

Basically , I'm trying to make a program that makes the Finch follow the object. I have made two classes : NewOption52 and FollowClass. Class NewOption52 contains a method which determines the properties of the GUI. Class FollowClass contains a main method which calls GUI method from class NewOption52 and it also contains several methods which dictates the Finch's behavior alongside with appending text to JTextArea feed.
When I connect the Finch and run the program , a GUI should appear and inside JTextArea should have text which says ""Please Place An Object in front of Finch And Then Tap Finch to Activate!\n". It didn't happen when I run the program.
Class NewOption52 :
import edu.cmu.ri.createlab.terk.robot.finch.Finch;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;
import javax.swing.*;
public class NewOption52 {
public static NewOption52 Op = new NewOption52();
public static JTextArea feed;
public static JButton halt;
public static JButton exit;
public static JFrame x ;
static protected Finch Grubert = new Finch();
//Method for determining the GUI
static void GUI()
{
final JFrame x = new JFrame("Finch Mission : Follow an Object!") ;
// How the window should be closed
x.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Adding a layout manager
x.setLayout(new FlowLayout());
x.setResizable(false);
x.setLocationRelativeTo(null);
// Adding components ( significantly a JTextArea being a feedback box ) and adding ActionListeners to each button
halt = new JButton("Halt!");
x.add(halt);
halt.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
feed.append("You have halted the program\n");
Grubert.stopWheels();
Grubert.setLED(0, 0, 0);
JOptionPane.showMessageDialog(x,"You have halted the program , click OK to go back and please wait for 3 seconds for Finch to start again");
Grubert.sleep(3000);
x.repaint();
}
});
exit = new JButton("Exit");
x.add(exit);
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Grubert.quit();
System.exit(0);
}
});
feed = new JTextArea(30,60);
JScrollPane feedscroll = new JScrollPane(feed);
x.add(feedscroll);
// Arrange components neatly inside the window
x.pack();
// Making the window visible once Window is called
x.setVisible(true);
}
}
Class FollowClass :
import edu.cmu.ri.createlab.terk.robot.finch.Finch;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class FollowClass {
private static Finch Grubert = null;
private static int TapCount = 0;
public static JTextArea feed;
public static JButton halt;
public static JButton exit;
public static JFrame x ;
//public Finch Grubert = new Finch();
public static void main(String[] args)
{
//refers to first method to start program
NewOption52.GUI();
}
public static void Finch()
{
Grubert = new Finch();
ProgramFollow();
}
private static void ProgramFollow() {
// Loop to wait for Finch to be tapped and an obstacle detected in front of the Finch
boolean StartProgram = true;
NewOption52.feed.append("Please Place An Object in front of Finch And Then Tap Finch to Activate!\n");
while (StartProgram)
{
// Conditional statement for same thing as mentioned above
if (Grubert.isTapped()==true && Grubert.isObstacleLeftSide()==true && Grubert.isObstacleRightSide()==true)
{
feed.append("Finch is activated! Object is detected!\n");
Grubert.setLED(red,0,0);
Grubert.setWheelVelocities(leftVelocity, rightVelocity);
// Triggers RunAgain to true so the program doesnt stop in one run in order for Finch to move continuosuly
boolean RunAgain=true;
while(RunAgain)
{
// Calling Movement method for Finch movements
Movement();
// Inside while RunAgain loop , there is the incremental function called TapCount to determine how many times the Finch has been tapped
if (Grubert.isTapped()==true)
{
TapCount++;
feed.append("You have tapped the Finch. If TapCount = 3 , the program will terminate only if the object is not moving\n");
feed.append("Number of Taps:" + TapCount + "\n");
if (TapCount==3 && Grubert.isObstacleLeftSide()==false && Grubert.isObstacleRightSide()==false)
{
Grubert.stopWheels();
Grubert.setLED(0, 0, 0);
TapCount = 1;
JOptionPane.showMessageDialog(x,"You have tapped the Finch twice when the object is moving. Please click OK and wait for 3 seconds. Make sure the object is not moving in order for program to terminate when you have tapped it twice");
Grubert.sleep(3000);
}
if (TapCount==3 && Grubert.isObstacleLeftSide()==true && Grubert.isObstacleRightSide()==true)
{
Grubert.quit();
System.exit(0);
}
}
}
}
}
}
// Method for Finch movements
private static void Movement()
{
if (Grubert.isObstacleLeftSide()==false && Grubert.isObstacleRightSide()==false)
{
// send message to the feedback box ("Object is Detected! Following it now!");
feed.append("Following the Object now!\n");
StraightMovement();
}
else if (Grubert.isObstacleLeftSide()==true && Grubert.isObstacleRightSide()==false)
{
feed.append("Object detected on the left side\n");
LeftMovement();
}
else if (Grubert.isObstacleLeftSide()==false && Grubert.isObstacleRightSide()==true)
{
feed.append("Object detected on the right side\n");
RightMovement();
}
else if (Grubert.isObstacleLeftSide()==true && Grubert.isObstacleRightSide()==true)
{
StopMovement();
}
}
// Area of variables declaration for easy value modifications
static int Buzz = 500;
static int BuzzDuration = 10;
static int red = 255;
static int green = 255;
static int leftVelocity = 100;
static int rightVelocity = 100;
static int leftTurnV = -50;
static int rightTurnV = -50;;
// Area of variables declaration for easy value modifications
private static void StraightMovement()
{
Grubert.setLED(0, green, 0);
Grubert.setWheelVelocities(leftVelocity, rightVelocity);
Grubert.buzz(Buzz, BuzzDuration);
}
private static void LeftMovement()
{
Grubert.setLED(0, green, 0);
Grubert.setWheelVelocities(leftTurnV, rightVelocity);
Grubert.buzz(Buzz, BuzzDuration);
}
private static void RightMovement()
{
Grubert.setLED(0, green, 0);
Grubert.setWheelVelocities(leftVelocity, rightTurnV);
Grubert.buzz(Buzz, BuzzDuration);
}
private static void StopMovement()
{
Grubert.setLED(red, 0 , 0);
Grubert.stopWheels();
}
}

how to refresh the colors of button contained in a JFrame?

I am coding a little game in which i have taken a grid of JButtons in a JFrame and i want to refresh the colors of the buttons contained in a JFrame,which is already visible.As explained below
void foo(){
mainFrame.setVisible(true);//mainFrame is defined at class level.
//color update code for the buttons.
mainFrame.setVisible(true);
}
Result i am getting is not as expected and my screen gets freeze .Isn't it the right way to achieve what i wanted?
EDIT
ok i am explaining it in detail what i want to achieve.i have a class,as:-
import javax.swing.*;
import java.awt.*;
import java.util.*;
class Brick extends JButton{
public void setRandomColors(){
int random = (int) (Math.random()*50);
if(random%13==0){
this.setBackground(Color.MAGENTA);
}
else if(random%10==0){
this.setBackground(Color.red);
}
else if(random%9==0){
this.setBackground(Color.yellow);
}
else if(random%7==0){
this.setBackground(Color.orange);
}
else if(random%2==0){
this.setBackground(Color.cyan);
}
else{
this.setBackground(Color.PINK);
}
}
public void setBlackColor(){
this.setBackground(Color.black);
}
}
class Grid {
JFrame mainGrid = new JFrame();
ArrayList<Brick> bunchOfBricks = new ArrayList<>();
int gridLength = 8;//gridlenth is equals to gridweight as i have considered a Square grid.
int totalBricks = gridLength*gridLength;
public void formBunchOfBricks(){
for(int i=0;i<totalBricks;i++){
bunchOfBricks.add(new Brick());
}
}
public void formColoredGrid(){
Brick aBrick;
mainGrid.setLayout(new GridLayout(8,8));
for(int i=0;i<totalBricks;++i){
aBrick = (bunchOfBricks.get(i));
aBrick.setRandomColors();
mainGrid.add(aBrick);
}
mainGrid.setVisible(true);//its ok upto here iam getting randomly colored Frame of Bricks or so called JButtons.
delay(15);//Sorry for this one,i warn you not to laugh after looking its defination.
}
/*
I want following function to do following things:-
1.it should firstly display the Grid whose all buttons are black Colored.
2.After some time the original colored,first Row of grid formed by formColoredGrid should be displayed and all the rest Rows should be black.
3.Then second row turns colored and all other rows should be black......and so on upto last row of Grid.
*/
public void movingRows(){
setGridBlack();
delay(1);//see in upper method,for this horrible thing.
for(int i=0;i<gridLength;++i){
setGridBlack();
for (int j=0;j<gridLength;++j){
Brick aBrick = bunchOfBricks.get((gridLength*i)+j);
aBrick.setRandomColors();//Bricks are colored Row by Row.
}
delay(5);//already commented this nonsense.
mainGrid.setVisible(true);//using setVisible again,although this frame is already visible,when i called formColoredGrid.
setGridBlack();
}
//oh! disappointing,i have almost broken my arm slamming it on table that why the function result in a screen full of black buttons.
}
public void setGridBlack(){
for(int i=0;i<totalBricks;i++){
bunchOfBricks.get(i).setBlackColor();
}
}
public void delay(int a){
for ( int i=0;i<90000000;++i){
for(int j=0;j<a;++j){
}
}
}
public static void main(String args[]){
Grid g1 = new Grid();
g1.formBunchOfBricks();
g1.formColoredGrid();
g1.movingRows();
}
}
Please Help me what is the way out?
Your problem is in code not shown here:
//color update code for the buttons.
You're likely running a loop that never ends on the Swing event thread, possibly a never-ending while loop that polls the state of something(a guess), freezing your GUI. Solution: don't do this; don't use a continuous polling loop. Instead, change the colors based on responses to events as Swing is event-driven.
For better more specific help, please show the offending code and tell us more about your program.
Edit
If you're trying to show colored rows, one by one marching down the board, then my guess is right, you'll want to use a Swing Timer, one that uses an int index to indicate which row is being displayed in color. You'd increment the index inside of the Timer's ActionPerformed class, and then when all rows have been displayed stop the Timer. For example something like so:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyGrid extends JPanel {
private static final int GRID_LENGTH = 8;
private static final Color BTN_BACKGROUND = Color.BLACK;
private static final Color[] COLORS = { Color.MAGENTA, Color.CYAN,
Color.RED, Color.YELLOW, Color.ORANGE, Color.PINK, Color.BLUE,
Color.GREEN };
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 800;
private JButton[][] buttonGrid = new JButton[GRID_LENGTH][GRID_LENGTH];
private Map<JButton, Color> btnColorMap = new HashMap<>();
private Random random = new Random();
public MyGrid() {
setLayout(new GridLayout(GRID_LENGTH, GRID_LENGTH));
for (int row = 0; row < buttonGrid.length; row++) {
for (int col = 0; col < buttonGrid[row].length; col++) {
JButton btn = new JButton();
btn.setBackground(BTN_BACKGROUND);
// !! add action listener here?
add(btn);
buttonGrid[row][col] = btn;
}
}
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void resetAllBtns() {
for (JButton[] row : buttonGrid) {
for (JButton btn : row) {
btn.setBackground(BTN_BACKGROUND);
}
}
}
private class TimerListener implements ActionListener {
private int row = 0;
#Override
public void actionPerformed(ActionEvent e) {
resetAllBtns(); // make all buttons black
if (row != buttonGrid.length) {
for (int c = 0; c < buttonGrid[row].length; c++) {
int colorIndex = random.nextInt(COLORS.length);
Color randomColor = COLORS[colorIndex];
buttonGrid[row][c].setBackground(randomColor);
// !! not sure if you need this
btnColorMap.put(buttonGrid[row][c], randomColor);
}
row++;
} else {
// else we've run out of rows -- stop the timer
((Timer) e.getSource()).stop();
}
}
}
private static void createAndShowGui() {
MyGrid mainPanel = new MyGrid();
JFrame frame = new JFrame("MyGrid");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Please have a look at the Swing Timer Tutorial as well.
Edit 2
You ask:
but what is the reason of failure of this program,is it the useless delay function?
Your delay method does nothing but busy calculations on the Swing event thread:
public void delay(int a) {
for (int i = 0; i < 90000000; ++i) {
for (int j = 0; j < a; ++j) {
}
}
}
It's little different from a crude attempt at calling Thread.sleep(...), and is crude because you can't explicitly control how long it will run as you can with thread sleep. Again, the problem is that you're making these calls on the Swing event dispatch thread or EDT, the single thread that is responsible for all Swing drawing and user interactions. Blocking this thread will block your program making it non-running or frozen.

Java slideshow image delay using paintComponent

I am putting together a slideshow program that will measure a user's time spent on each slide. The slideshow goes through several different magic tricks. Each trick is shown twice. Interim images are shown between the repetition. Transition images are shown between each trick.
On the first repetition of a trick the JPanel color flashes on the screen after a click before the next image is shown. This doesn't happen during the second repetition of the same trick. It's possible that the image is taking too long to load.
Is there an easy way to pre-load the images so that there isn't a delay the first time through?
NOTE: Original code deleted.
EDIT 1/10/2013: This code now works on slower machines. trashgod's second addendum helped the most. The mouseClick control structure periodically asks SwingWorker classes to load 40 images or less of the current trick while also setting the used images to null. I have simplified my code down for this to just two Image[]s and added a main method so it stands alone. Images are still required to run though. This is now pretty bare bones code, and if you're trying to make a slideshow with a lot of images I think it would be a good place to start.
NOTE: I think I figured out how to properly implement SwingWorker while still using multiple Image[]s. trashgod and kleopatra is this implementation in-line with what you were suggesting? I didn't end up using publish and process since I couldn't figure out how to get that to work appropriately with an indexed array, but because the StringWorker doesn't load all images in the array (only 40), and the code calls StringWorker every 20 images, there should be a pretty good buffer.
EDIT 1/10/2013 Changed out MouseListener by instead extending MouseAdapter on my Mouse class. Also fixed my paintComponent method to include a call to super.paintComponent(g).
Added publish/process methods to my SwingWorker class ImageWorker. Added a wrapper class, ArrayWrapper to allow passing imageArray[i] and its corresponding index int i with publish to process.
package slideshow3;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.util.List;
public class SlideShow3 extends JFrame
{
//screenImage will be replaced with each new slide
private Image screenImage;
private int width;
private int height;
//Create panel for displaying images using paintComponent()
private SlideShow3.PaintPanel mainImagePanel;
//Used for keybinding
private Action escapeAction;
//Image array variables for each trick
private Image[] handCuffs; //h
private Image[] cups; //c
//Used to step through the trick arrays one image at a time
private int h = 0;
private int c = 0;
//Used by timeStamp() for documenting time per slide
private long time0 = 0;
private long time1;
public SlideShow3()
{
super();
//Create instance of each Image array
handCuffs = new Image[50];
cups = new Image[176];
//start(handCuffsString);
start("handCuffs");
try
{
screenImage = ImageIO.read(new File("images/begin1.jpg"));
}
catch (IOException nm)
{
System.out.println("begin");
System.out.println(nm.getMessage());
System.exit(0);
}
/******************************************
* Removes window framing. The next line sets fullscreen mode.
* Once fullscreen is set width and height are determined for the window
******************************************/
this.setUndecorated(true);
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
width = this.getWidth();
height = this.getHeight();
//Mouse click binding to slide advance control structure
addMouseListener(new Mouse());
//Create panel so that I can use key binding which requires JComponent
mainImagePanel = new PaintPanel();
add(mainImagePanel);
/******************************************
* Key Binding
* ESC will exit the slideshow
******************************************/
// Key bound AbstractAction items
escapeAction = new EscapeAction();
// Gets the mainImagePanel InputMap and pairs the key to the action
mainImagePanel.getInputMap().put(KeyStroke.getKeyStroke("ESCAPE"), "doEscapeAction");
// This line pairs the AbstractAction enterAction to the action "doEnterAction"
mainImagePanel.getActionMap().put("doEscapeAction", escapeAction);
/******************************************
* End Key Binding
******************************************/
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
SlideShow3 show = new SlideShow3();
show.setVisible(true);
}
});
}
//This method executes a specific SwingWorker class to preload images
public void start(String e)
{
if(e.equals("handCuffs"))
{
new ImageWorker(handCuffs.length, h, e).execute();
}
else if(e.equals("cups"))
{
new ImageWorker(cups.length, c, e).execute();
}
}
//Stretches and displays images in fullscreen window
private class PaintPanel extends JPanel
{
#Override
public void paintComponent(Graphics g)
{
if(screenImage != null)
{
super.paintComponent(g);
g.drawImage(screenImage, 0, 0, width, height, this);
}
}
}
/******************************************
* The following SwingWorker class Pre-loads all necessary images.
******************************************/
private class ArrayWrapper
{
private int i;
private Image image;
public ArrayWrapper(Image image, int i)
{
this.i = i;
this.image = image;
}
public int getIndex()
{
return i;
}
public Image getImage()
{
return image;
}
}
private class ImageWorker extends SwingWorker<Image[], ArrayWrapper>
{
private int currentPosition;
private int arraySize;
private String trickName;
private Image[] imageArray;
public ImageWorker(int arraySize, int currentPosition, String trick)
{
super();
this.currentPosition = currentPosition;
this.arraySize = arraySize;
this.trickName = trick;
}
#Override
public Image[] doInBackground()
{
imageArray = new Image[arraySize];
for(int i = currentPosition; i < currentPosition+40 && i < arraySize; i++)
{
try
{
imageArray[i] = ImageIO.read(new File("images/" + trickName + (i+1) + ".jpg"));
ArrayWrapper wrapArray = new ArrayWrapper(imageArray[i], i);
publish(wrapArray);
}
catch (IOException e)
{
System.out.println(trickName);
System.out.println(e.getMessage());
System.exit(0);
}
}
return imageArray;
}
#Override
public void process(List<ArrayWrapper> chunks)
{
for(ArrayWrapper element: chunks)
{
if(trickName.equals("handCuffs"))
{
handCuffs[element.getIndex()] = element.getImage();
}
else if(trickName.equals("cups"))
{
cups[element.getIndex()] = element.getImage();
}
}
}
#Override
public void done()
{
try
{
if(trickName.equals("handCuffs"))
{
handCuffs = get();
}
else if(trickName.equals("cups"))
{
cups = get();
}
}
catch(InterruptedException ignore){}
catch(java.util.concurrent.ExecutionException e)
{
String why = null;
Throwable cause = e.getCause();
if(cause != null)
{
why = cause.getMessage();
}
else
{
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
}
/******************************************
* End SwingWorker Pre-Loading Classes
******************************************/
//Prints out time spent on each slide
public void timeStamp()
{
time1 = System.currentTimeMillis();
if(time0 != 0)
{
System.out.println(time1 - time0);
}
time0 = System.currentTimeMillis();
}
/******************************************
* User Input Classes for Key Binding Actions and Mouse Click Actions
******************************************/
private class EscapeAction extends AbstractAction
{
#Override
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
}
public class Mouse extends MouseAdapter
{
#Override
public void mouseClicked(MouseEvent e)
{
if(!(h<handCuffs.length) && !(c<cups.length))
{
timeStamp();
System.exit(0);
}
else if(h<handCuffs.length)
{
timeStamp();
screenImage = handCuffs[h];
repaint();
System.out.print("handCuffs[" + (h+1) + "]\t");
h++;
//purge used slides and refresh slide buffer
if(h == 20 || h == 40)
{
for(int i = 0; i < h; i++)
{
handCuffs[i] = null;
}
start("handCuffs");
}
if(h == 45)
{
start("cups");
}
}
else if(c<cups.length)
{
timeStamp();
screenImage = cups[c];
repaint();
System.out.print("cups[" + (c+1) + "]\t");
c++;
//purge used slides and refresh slide buffer
if(c == 20 || c == 40 || c == 60 || c == 80 || c == 100 || c == 120 || c == 140 || c == 160)
{
for(int i = 0; i < c; i++)
{
cups[i] = null;
}
start("cups");
}
}
}
}
/******************************************
* End User Input Classes for Key Binding Actions and Mouse Click Actions
******************************************/
}
This example uses a List<ImageIcon> as a cache of images returned by getImage(). Using getResource(), the delay is imperceptible. The next and previous buttons are bound to the Space key by default.
Addendum: You can control navigation by conditioning a button's setEnabled() state using an instance of javax.swing.Timer, for example.
Addendum: Your second example waits until the mouse is clicked to begin reading an image, an indeterminate process that may return a copy immediately or may not complete until after repaint(). Instead, begin reading the images in the background using ImageIO.read(), as shown here. You can process() your List<Image> and show progress, as seen here. The SwingWorker can be launched from the initial thread, running while you subsequently build your GUI on the EDT. You can display the first image as soon as it is processed.

Categories

Resources