I am designing a matching memory game, I am almost done with it and everything is working as it should be, however, when the user has opened two different cards the program won't pause(wait) few seconds so the user can see what the second card was.
I have tried using a long for loop operation but encountered the same problem. I have tried Thread.sleep, TimeUnit.SECONDS.sleep, Task and Platform.runLater.
The program opens the card and closes it instantly THEN it waits for the specified duration, keeping in mind that I am calling pauseThread after open and before close functions.
I have tried the above suggestions but they are leading me no where and I can't seem to find where the problem is with my code or where should I place the pauseThread. Thanks in advance.
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class MemoryMatchingGame extends Application{
private static Card selectedCard=null; // This is to save a reference for the first card to use in comparison
private static int numOfCorrectPairs = 0; // Keeping track of how many cards the user got correct
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
String[] images = {"C:\\Users\\userName\\Desktop\\Project#4\\1.png", // This is a string array to store images locations
"C:\\Users\\userName\\Desktop\\Project#4\\2.png",
"C:\\Users\\userName\\Desktop\\Project#4\\3.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\4.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\5.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\6.png",
"C:\\Users\\userName\\Desktop\\Project#4\\7.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\8.jpg"};
ArrayList<Card> listOfCards = new ArrayList<Card>();
for(int i=0; i<images.length; i++) { // This for loop will add each image twice to the array list
listOfCards.add(new Card(images[i]));
listOfCards.add(new Card(images[i]));
}
Collections.shuffle(listOfCards); // Shuffling the deck of cards
primaryStage.setTitle("Memory Matching Game");
HBox hb = new HBox();
VBox firstColoumn = new VBox();
for(int i=0; i<4; i++)
firstColoumn.getChildren().add(listOfCards.get(i));
VBox secondColoumn = new VBox();
for(int i=4; i<8; i++)
secondColoumn.getChildren().add(listOfCards.get(i));
VBox thirdColoumn = new VBox();
for(int i=8; i<12; i++)
thirdColoumn.getChildren().add(listOfCards.get(i));
VBox fourthColoumn = new VBox();
for(int i=12; i<16; i++)
fourthColoumn.getChildren().add(listOfCards.get(i));
hb.getChildren().addAll(firstColoumn, secondColoumn, thirdColoumn, fourthColoumn);
Scene scene = new Scene(hb, 460, 450);
primaryStage.setScene(scene);
primaryStage.show();
}
private class Card extends Button {
private String imageLocation; // To store the destination of the image
private Image img; // To store a reference of the image to be used when setting graphic on a button
public Card(String imageLocation) throws FileNotFoundException {
this.imageLocation = imageLocation;
FileInputStream fis = new FileInputStream(imageLocation);
img = new Image(fis);
setPrefSize(150, 150);
setOnMouseClicked(e -> {
if(isCardOpen()==true)
return; // To ensure no action is made once an image is already opened and the user clicked on it again
if(selectedCard==null) {// This will test if the user has a card open already for comparison or not, if not it will store a reference to the card to use to compare once another card is opened
selectedCard = this;
open();
}
else { // If we enter this statement, this means the user has a card open already and we are ready to perform comparison
open(); // First action taken is to reveal the second card then perform comparison
if(this.isEqual(selectedCard)) {
numOfCorrectPairs++;
System.out.println("Got one");
}
else {
//Get program to pause here
Hold pauseThread = new Hold();
pauseThread.run();
System.out.println("After pausing");
this.close();
selectedCard.close();
}
selectedCard=null; // This will nullify the variable so that we are able to perform comparison again for two other cards
} // End of else statement
}); // End of actionHandler
close(); // This will ensure whenever a card is created it is set face-down
}
private void close() {
setGraphic(null);
}
public void open() {
setGraphic(new ImageView(img));
System.out.println("Open");
}
private boolean isCardOpen() {
return this.getGraphic()!=null;
}
private boolean isEqual(Card selectedCard) {
return this.imageLocation.equals(selectedCard.imageLocation);
}
}
private class Hold extends Thread{
public void run() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Everything in your code is running in the JavaFX Application Thread. You don't want to pause this thread because it will lock your GUI. As has already been mentioned, you are starting another thread and putting it to sleep, but this doesn't add delay to your GUI that is running in the JavaFX Thread.
An alternative approach would be to use Platform.runLater(). The Hold thread can invoke a method in the JavaFX thread that implements a Platform.runLater() runnable. The runnable is a short lambda that holds the code to close the selected card. The timing may vary slightly from 3000 ms, but you don't have much going on in the JavaFX thread and it doesn't seem critical for this application.
Here are the modifications to try.
First modify the Hold class to include a constructor to pass in the Card object. Then call the closeAfterPause() method on card.
private class Hold extends Thread {
private Card card;
public Hold(Card card) {
this.card = card;
}
public void run() {
try {
TimeUnit.SECONDS.sleep(3);
card.closeAfterPause();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Then create the closeAfterPause() method in the MemoryMatchingGame class.
private void closeAfterPause() {
Platform.runLater(() -> {
System.out.println("After Pausing");
close();
selectedCard.close();
});
}
Then modify the else part of your if-else statement as follows
else {
//Get program to pause here
Hold pauseThread = new Hold(this);
new Thread(pauseThread).start();
}
FX comes with a rich set of Animation/Timeline support - there's no need for falling back onto bare Threads. The most simple form of getting wait-for-xx is to use a Timeline configured with xx and an actionHandler that does something when ready:
Timeline holdTimer = new Timeline(new KeyFrame(
Duration.seconds(2), e -> closeCards()));
Also it's a good idea to centralize all logic outside of a Control. Actually, you should never-ever extend a view for the purpose to include view-unrelated logic. So your long-time goal should be to
extract all single card logic from Card into a CardModel which exposes properties like f.i. image, id, open, disposed
use a plain Button, configure and bind its properties to model properties as appropriate
centralize all game logic like timing, selecting, when opening is allowed, when succeed into a game controller
As I don't want to spoil your fun in doing that - I'll just post a little outline in the direction of the last bullet. Its responsibilities so far
provide api to open a single card
provide api to end a turn: either match or close cards
internals to keep track of opened cards and timing
The snippets just re-mixes your code a bit, moving game logic from the button into the controller (aka: here simply the outer class) and setting the button's action handler to access the controller.
private Card firstCard;
private Card secondCard;
private Timeline holdTimer = new Timeline(new KeyFrame(
Duration.millis(2000), e -> closeCards()));
public void closeCards() {
if (firstCard == null || secondCard == null) {
System.out.println("error!!");
return;
}
if (firstCard.isEqual(secondCard)) {
System.out.println("success");
firstCard.setDisable(true);
secondCard.setDisable(true);
firstCard = null;
secondCard = null;
} else {
firstCard.close();
secondCard.close();
firstCard = null;
secondCard = null;
}
}
public void openCard(Card card) {
if (card.isCardOpen()) return;
if (holdTimer.getStatus() == Status.RUNNING) return;
if (firstCard == null) {
firstCard = card;
firstCard.open();
} else if (secondCard == null) {
secondCard = card;
secondCard.open();
holdTimer.playFromStart();
}
}
// Dont! dont, dont!!! ever extend a Control
//**TBD**: Move open/close state logic into a CardModel
// then configure a plain Button with the properies of that model
private class Card extends Button {
private String imageLocation; // To store the destination of the image
// private Image img; // To store a reference of the image to be used when setting graphic on a button
public Card(String imageLocation) throws FileNotFoundException {
this.imageLocation = imageLocation;
setPrefSize(150, 150);
setOnAction(e -> openCard(this));
}
public void close() {
setText("");
}
public void open() {
setText(imageLocation);
System.out.println("Open");
}
public boolean isCardOpen() {
return getText() != null && getText().length() > 0;//this.getGraphic()!=null;
}
private boolean isEqual(Card selectedCard) {
if (selectedCard == null) return false;
return this.imageLocation.equals(selectedCard.imageLocation);
}
}
I have not been able to find any good questions regarding my predicament. I am trying to count/check how many times a specific item is clicked via an actionListener but am unsure of how to use an actionListener/EventHandler to document the click. This is being done in JavaFX.Pardon the potentially noobish question.
correctUrl = getCorrectUrl(); //Correct image for set
wrongUrl = getWrongUrl();
initialPos(); //everything is placed into default.
imageOne.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
imageOne.setOnMouseClicked((MouseEvent e) -> {
imageOne = flipToCard(imageOne, 1);
});
returnCardOne();
System.out.println("Tile pressed ");
event.consume();
});
The ultimate goal of the code is to notice two images have been clicked and then check to see if their URL == each-other.
If the URLs are equal, the Images should be equal. So why not compare Images? This little app demos what you are trying to achieve. Comments in the code.
Main:
import java.util.ArrayList;
import java.util.List;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
*
* #author Sedrick
*/
public class JavaFXApplication51 extends Application {
#Override
public void start(Stage primaryStage) {
List<ImageViewTile> imageViews = new ArrayList();
List<ImageViewTile> cardsBeingMatched = new ArrayList();//Used to keep up with the current two cards that are pressed inorder to deteremine if they are a match
Image initialImage = new Image(getClass().getResourceAsStream("cardBack_blue1.png"));
Image ace = new Image(getClass().getResourceAsStream("cardSpadesA.png"));
Image king = new Image(getClass().getResourceAsStream("cardSpadesK.png"));
imageViews.add(new ImageViewTile(initialImage, ace));
imageViews.add(new ImageViewTile(initialImage, king));
imageViews.add(new ImageViewTile(initialImage, ace));
imageViews.add(new ImageViewTile(initialImage, king));
for(ImageViewTile view : imageViews)
{
//Set ImageViews' onMouseClicked handler
view.setOnMouseClicked(event->{
if(!view.isShowing())//If card face value is not showing
{
view.showFrontImage();//show it.
cardsBeingMatched.add(view);//Add card being clicked to list so it can be compared against the next card
if(cardsBeingMatched.size() == 2)//Once two cards are in the list, see if they are equal.
{
if(cardsBeingMatched.get(0).getImage().equals(cardsBeingMatched.get(1).getImage()))//If cards are equal a match is found
{
System.out.println("Match");
cardsBeingMatched.clear();//clear the list to prepare to compare the next two cards that are clicked
}
else//If cards are not equal
{
System.out.println("No match");
//wait half a second and flip cards back over
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(.5), (event1) -> {
System.out.println(".5 seconds need to pass before another mouse click!");
}));
timeline.setCycleCount(1);
timeline.play();
timeline.setOnFinished(event1->{
cardsBeingMatched.get(0).showBackImage();
cardsBeingMatched.get(1).showBackImage();
cardsBeingMatched.clear();//clear the list to prepare to compare the next two cards that are clicked
});
}
}
}
});
}
GridPane root = new GridPane();
for(int i = 0; i < imageViews.size(); i++)
{
root.add(imageViews.get(i), i % 2, i / 2);//Add ImageViews to the GridPane
}
Scene scene = new Scene(root, 280, 380);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
ImageViewTitle Class:
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
/**
*
* #author Sedrick
*/
public final class ImageViewTile extends ImageView{
private boolean showing;
private final Image backImage;
private final Image frontImage;
public ImageViewTile(Image backImage, Image frontImage) {
this.backImage = backImage;
this.frontImage = frontImage;
this.setImage(backImage);
showing = false;
}
public void showBackImage()
{
this.setImage(backImage);
showing = false;
}
public void showFrontImage()
{
this.setImage(frontImage);
showing = true;
}
public boolean isShowing()
{
return showing;
}
}
I created this class to help me keep up with the ImageView's different states.
I'm new to Java Swing and I have been working on creating a Connect 4 Game which supports multiplayers through a server with a gameRoom. I have been working on this particular problem for almost 2 days and while solving it have fixed problems such as stopped the use of Thread.sleep and thoroughly tested that the Game object is passed on correctly to and from the server.
The way I architected is that each move is submitted through the model's make move command. In order to refresh the GUI, the server sends back a new Game object to the model and marks the controller attribute 'setRepaint' as true. Then, a timer periodically checks if this attribute is true and calls the repaintGrid() method.
After many hours of trying to get this to work, I cannot get the game panels to repaint.
Some points which might help:
If I quit the application and restart it with a Game object that already has moves on it, the panels are painted. The problem is with the repaint method.
The model is static and gets it Game attribute updated every time the Connect4App.model.getGameFromServer() is called. Not sure if this would cause problems but if I print the panels that are being repainted as red/blue, I can verify that the game object is updated successfully by the server on each iteration.
The frame hierarchy is the following: The guiMain is a container for the gamePanel which has a gridlayout, each filled in by a GridPanel panel. The Grid panels are essentially the slots for the tokens of the Connect4 Game and those are the ones that I try to update in the repaintGrid method
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GameController {
MouseAdapter me;
private JPanel gamePanel;
private boolean setRepaint = false;
/**
* Constructor for the Game Controller. Takes in a view and a model
*
* #param view
* #param model
*/
public GameController() {
setupGridPanels();
setupMouseAdapter();
Connect4App.frame.setContentPane(Connect4App.guiMain);
Connect4App.frame.setTitle("Game View");
goIntoTimer();
}
/**
* Repaint Boolean used by timer. Set to true by external program
*/
public void setRepaint() {
this.setRepaint = true;
}
/**
* Swing Timer which checks if it needs to repaint every 8 seconds and if
* so, calls repaintGrid
*/
private void goIntoTimer() {
Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Connect4App.model.getGameFromServer();
if (setRepaint == true) {
repaintGrid();
setRepaint = false;
}
}
});
timer.setRepeats(true);
timer.setDelay(8000);
timer.start();
}
/**
* Sets up the Initial Game Panels in the Connect4App.guiMain panel
*/
private void setupGridPanels() {
this.gamePanel = new JPanel();
this.gamePanel.removeAll();
// setting up the layout for, the game board.
this.gamePanel.setLayout(new GridLayout(0, Connect4App.model.getGame().getGrid()[0].length));
int numberOfRows = Connect4App.model.getGame().getGrid().length;
int numberOfColumns = Connect4App.model.getGame().getGrid()[0].length;
for (int r = 0; r < numberOfRows; r++) {
for (int c = 0; c < numberOfColumns; c++) {
Connect4App.guiMain.setCircleArc(r, c, new GridPanel(r, c));
this.gamePanel.add(Connect4App.guiMain.getCircleArcs()[r][c]);
}
}
Connect4App.guiMain.add(this.gamePanel);
}
/**
* Sets up the mouse pressed event handleres for every panel
*/
private void setupMouseAdapter() {
MouseAdapter mc = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mc) {
GridPanel cell = (GridPanel) mc.getSource();
// this is the column that should go in the MakeMove message
int column = cell.getColumn();
int row = cell.getRow();
if (Connect4App.model.getGame().getGrid()[row][column].getState() == 0) {
System.out.println("attempting to make move");
Connect4App.model.makeMove(column);
}
}
};
for (int r = 0; r < Connect4App.model.getGame().getGrid().length; r++) {
for (int c = 0; c < Connect4App.model.getGame().getGrid()[0].length; c++) {
Connect4App.guiMain.getCircleArcs()[r][c].addMouseListener(mc);
}
}
}
void repaintGrid() {
// --> This is supposed to be working
System.out.println("repainting");
for (int r = 0; r < Connect4App.model.getGame().getGrid().length; r++) {
for (int c = 0; c < Connect4App.model.getGame().getGrid()[0].length; c++) {
Connect4App.guiMain.getCircleArcs()[r][c].validate();
Connect4App.guiMain.getCircleArcs()[r][c].repaint();
}
}
}
}
Any help would be appreciated :-D
It turns out the I was having a problem with sending the same object back and fourth through objectoutputstreams (the game state) without reseting the streams and so this was causing the client not to receive updates all of the times. The repainting code above was working. Closing the thread, thanks again.
Disclaimer: this is a (frustrating) homework related problem.
I'm having odd results when I draw my objects on screen. I want this...I draw first object then draw second object when I select third object to draw the screen clears and I have to start the process again....what i get is...I draw first object, I draw second object, I go to draw third object screen clears...I select third object but SECOND object is what appears on screen. Please help point me in right direction.
package ui.panels;
import java.awt.Choice;
import java.awt.Panel;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import model.Model;
import interfaces.Resettable;
public class ChoicePanel extends Panel implements Resettable{
public int i = 0;
/**
*
*/
private static final long serialVersionUID = 1L;
Model model;
Choice selection;
public ChoicePanel(Model mdl) {
model = mdl;
selection = new Choice();
for (String msg : Model.selections) {
selection.add(msg);
}
selection.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if(i==1) {//drop down clicked three times)
System.out.println("ChoicePanel says i == "+i);
model.setMessage(selection.getSelectedItem());
model.setCurrentShapeType(selection.getSelectedItem());
//model.repaint();
++i;
}else if(i==2){
System.out.println("ChoicePanel says i == "+i);
model.setMessage(selection.getSelectedItem());
//model.setCurrentShapeType(selection.getSelectedItem());
model.resetComponents();
//--i;
}else{
model.setMessage(selection.getSelectedItem());
//this line is what sends a value to shape that is drawn on screen
model.setCurrentShapeType(selection.getSelectedItem());
//model.repaint();
++i;
}
}
});
this.add(selection);
}
public void resetComponents() {
System.out.println("resetComponents from ChoicePanel");
//this resets the drop down list selection array to the first choice on the list
selection.select(0);
//this sets selected item in the selection array set in the above line
//model.setMessage(selection.getSelectedItem());
i=0;
model.repaint();
}
}
Within else if(i==2){ ... } you don't increment i, it'll never get past 2.
} else if(i==2){
System.out.println("ChoicePanel says i == "+i);
model.setMessage(selection.getSelectedItem());
//model.setCurrentShapeType(selection.getSelectedItem());
model.resetComponents();
++i; // Increment here
}
i have written an application, but for some reason it keeps peaking at 100%. I ran a profile r on a few of the classes and a report show that isReset() and isRunning() seems to be called alot of times. Do you see anything wrong please inform me. thanks
Class 1 is the only class that uses the isReset() code so i hope this helps u guys in detecting the error
Class 1
package SKA;
/*
* ver 0.32 June 2009
*
* Bug Fix Release:
*
* Fixed Array resize
* Fixed Red Black Tree delete method
* Fixed Red Black Tree save/read option
* Update help file
*
*/
/*
* Additions:
* ver 0.30 May 2009
*
* Added Red Black Tree structure
* Added Delete method for canvases
* Added Array structure
* Added ability to recolor nodes.
* Added Bubble Sort Algorithm
* Added Insertion Sort Algorithm
* Added Shell Sort Algorithm
* Added Selection Sort Algorithm
* Added Quick Sort Algorithm
* Added Red Black Tree Search Algorithm
* Added Black Height Check Algorithm
* Bug fix in canvas - could not delete canvas properly
*/
// Additions:
/* ver 0.25 August 2004
* Added recursion in SkaExecutionPanel by adding SkaFunction
* and using desktop internal panes.
*
* Added binary tree node annotation - text and drawn
* Added subtree highlight feature to VizBinaryTreeNode using SkaRectangle
* Improved node highlighting and selection scheme in VizBinaryTrees/VizDS
* Added Binary tree save and read methods
* Added visual subtree deletion (has bug)
*
* Added ability to set breaks from within algorithm
* Added tooltip messages to SkaProgram/SkaFunction to show variable values
* Added simple value input and output methods to SkaProgram/SkaFunction
* Added SkaTriangle.
* Added Font Adjustment and Color scheme options to show on overhead projectors
*
* Found bug in SkaGraph deleteVertex (with edges)
*/
/* ver 0.16 October 15, 2001
Added Graph save and read methods.
Save is an instance method, while read is a class method.
Added circular layout for graphs,
Added fit/adjust graph layout to plate size method.
Added label editing for Binary Trees and Graphs.
SkaLabels (glyphs) now truncate the string displayed to the width specified
in the constructor.
*/
/* ver 0.15 July 21, 2001
Fixed Reset function in Execution using exceptions so that Ska Algorithms
can be run repeatedly without quitting the entire Ska System.
This also allows trying the same program on different data structures.
Problems with reset so far:
1. Reset message to user can appear much later.
I think this is an I/O sequencing problem and it should go away if
a message status GUI area is used.
2. Bound variable names remain afterwards,
e.g. Graph bound to G will still show name as G after
algorithm is interrupted.
Fixed problem with multiple input requests in 0.14 - by adding another
wait call which waits on before asking for input.
Also introduced trial orderly layout of canvas and program windows ,
which fixes problem in 0.14
*/
/* ver 0.14 July 18, 2001
Added subclasses of SkaProgram, so that multiple programs
can run simultaneously.
Problem - when multiple programs start, their windows overlay each other
Problem - Send DS to algorithm can get confused, if an algorithm
requests input while another is waiting on input or if
two algorithms request input at the same time
*/
/* ver 0.13
Added BinaryTree - does not have node value display yet.
Added arrows on edges of directed graphs
*/
/* ver 0.12
Added VizElementListener - separated from VizElement
Element Input menu item only highlights when input for that DS is requested
DS Input has been cleaned up
*/
/* ver 0.11
can ask user to select individual elements, e.g. vertices
removed standard java cloning code which wasn't being used anyway
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.border.BevelBorder;
import javax.swing.border.SoftBevelBorder;
// TimerQueue
public class SkaTest {
public static final int WIDTH = 500;
public static final int HEIGHT = 500;
public static final int CANVAS_X = 100;
public static final int CANVAS_Y = 100;
public static final int CANVAS_FRAME_WIDTH = WIDTH+100;
public static final int CANVAS_FRAME_HEIGHT = HEIGHT + 100;
public static final int EXEC_WIDTH = 550;
public static final int EXEC_HEIGHT = 400;
static VizDSList dsList = new VizDSList();
static SkaCanvas canvas = new SkaCanvas(dsList);
static JFrame canvasFrame = new JFrame("Data Structure Canvas");
static JMenuBar menuBar = new JMenuBar();
static JMenu algorithmMenu = new JMenu("Algorithm");
static JMenu dsMenu = new JMenu("Create");
static JMenu helpMenu = new JMenu ("Help");
static JLabel status = new JLabel(" ");
static SkaProgram[] alg;
static JFrame execFrame[];
static SkaExecutionPanel execPanel[];
public static void setupFrames(int nAlgs) {
int i;
for (i=0; i < nAlgs; i++) {
// execFrame[i] = new JFrame("Execution Control Panel "+(i+1));
execFrame[i] = new JFrame();
execPanel[i] = new SkaExecutionPanel(execFrame[i]);
}
canvas.setMinimumSize(new Dimension(WIDTH, HEIGHT));
canvasFrame.setSize(CANVAS_FRAME_WIDTH, CANVAS_FRAME_WIDTH);
canvasFrame.getContentPane().setLayout(new BorderLayout(10,7));
// canvasFrame.getContentPane().setPreferredSize(new Dimension(WIDTH, HEIGHT));
canvasFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
// canvas.setMinimumSize(new Dimension(WIDTH, HEIGHT));
for (i=0; i < nAlgs; i++) {
execFrame[i].setSize(EXEC_WIDTH, EXEC_HEIGHT);
// execFrame[i].getContentPane().setLayout(new BorderLayout(10,7));
execFrame[i].addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
execPanel[i].setBorder(new SoftBevelBorder(BevelBorder.RAISED));
// execFrame[i].setContentPane(execPanel[i]);
execFrame[i].getContentPane().add("Center", execPanel[i]);
// execFrame[i].setLocation(CANVAS_X +CANVAS_FRAME_WIDTH, CANVAS_Y + i*EXEC_HEIGHT);
execFrame[i].setLocation(CANVAS_X +CANVAS_FRAME_WIDTH + i*30, CANVAS_Y + i*50);
}
canvas.setBorder(new SoftBevelBorder(BevelBorder.RAISED));
canvasFrame.getContentPane().add("Center", new JScrollPane(canvas) );
// canvasFrame.getContentPane().add("Center", new JScrollPane(canvas, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS) );
canvasFrame.getContentPane().add("South", status);
canvasFrame.setLocation(CANVAS_X, CANVAS_Y);
JMenu fileMenu = new JMenu("File");
JMenuItem quitItem = new JMenuItem("Quit");
//TODO Add quit listener
quitItem.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent arg0) {
//System.exit(0);
int again = JOptionPane.showConfirmDialog(null, "Are you sure you want to exit system", "Exiting", JOptionPane.YES_NO_OPTION);
if (again == JOptionPane.YES_OPTION)
{
System.exit(0);
}
}
}
);
fileMenu.add(quitItem);
menuBar.add(fileMenu);
menuBar.add(algorithmMenu);
// menuBar.add(dsMenu);
menuBar.add(helpMenu);
JMenuItem help = new JMenuItem ("Help Contents");
//help.setMnemonic(KeyEvent.VK_H);
//TODO Fix this method
help.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, ActionEvent.CTRL_MASK));
help.addActionListener(new ActionListener()
{
/*
#Override
public void actionPerformed(ActionEvent arg0) {
JOptionPane.showMessageDialog(null, "Alot of the functionality have not yet been included in this version\nCurrently working on the automation features now!", "SKA 0.2 Beta", JOptionPane.WARNING_MESSAGE);
}
*/
public void actionPerformed(ActionEvent arg0) {
try {
Runtime.getRuntime().exec("hh.exe C:/ska.chm");
} catch (IOException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "File not found", "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
JMenuItem about = new JMenuItem ("About SKA");
about.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
JOptionPane.showMessageDialog(null, "SKA Version 0.1 Beta");
}
});
helpMenu.add(help);
helpMenu.add(about);
canvasFrame.setJMenuBar(menuBar);
}
/** The create menu item */
public static void createProgram(int i) {
JMenuItem algItem;
switch (i) {
case 0 :
alg[0] = new RedBlackValidate(canvas, execPanel[0]);
execFrame[0].setTitle("Validate Algorithm");
System.out.println("Validate Algorithm");
algItem = new JMenuItem("Validate Algorithm");
algorithmMenu.add(algItem);
break;
/* case 0 :
alg[0] = new BreadthFirstSearch(canvas, execPanel[0]);
execFrame[0].setTitle("BFS Graph Algorithm");
// System.out.println("BreadthFirstSearch");
algItem = new JMenuItem("BFS Graph Algorithm");
algorithmMenu.add(algItem);
break;
case 1:
alg[1] = new LevelOrderAlgorithm(canvas, execPanel[1]);
execFrame[1].setTitle("Level Order Tree Algorithm");
System.out.println("LevelOrderAlgorithm");
algItem = new JMenuItem("Level Order Tree Algorithm");
algorithmMenu.add(algItem);
break;
case 2:
alg[2] = new BinarySearchTreeAlgRecursive(canvas, execPanel[2]);
execFrame[2].setTitle("BinaryTreeSearchRec Algorithm");
System.out.println("BinaryTreeSearchRec Algorithm");
algItem = new JMenuItem("BinaryTreeSearchRec Algorithm");
algorithmMenu.add(algItem);
break;
case 3:
alg[3] = new BinarySearchTreeAlgIterative(canvas, execPanel[3]);
execFrame[3].setTitle("BinaryTreeSearchIter Algorithm");
System.out.println("BinaryTreeSearchIter Algorithm");
algItem = new JMenuItem("BinaryTreeSearchIter Algorithm");
algorithmMenu.add(algItem);
break;
case 4:
alg[4] = new RebBlackTreeSearch (canvas, execPanel[4]);
execFrame[4].setTitle("Red Black Search Algorithm");
System.out.println("Red Black Search Algorithm");
algItem = new JMenuItem("Red Black Search Algoithm Algorithm");
algorithmMenu.add(algItem);
break;
case 5:
alg[5] = new ArrayInsertionSortAlg (canvas, execPanel[5]);
execFrame[5].setTitle("Array Insertion Sort Algorithm");
System.out.println("Array Insertion Sort");
algItem = new JMenuItem("Array Insertion Sort Algorithm");
algorithmMenu.add(algItem);
break;
case 6:
alg[6] = new ArraySelectionSortAlg (canvas, execPanel[6]);
execFrame[6].setTitle("Array Selection Sort Algorithm");
System.out.println("Array SelectionSearch");
algItem = new JMenuItem("Array Selection Sort Algorithm");
algorithmMenu.add(algItem);
break; */
default:
break;
}
}
public static void main(String args[]) {
int i, nAlgs = 1; //nAlgs = 7;
alg = new SkaProgram[nAlgs];
execPanel = new SkaExecutionPanel[nAlgs];
execFrame = new JFrame[nAlgs];
// canvas.setDebugGraphicsOptions(DebugGraphics.BUFFERED_OPTION);
setupFrames(nAlgs);
canvasFrame.setVisible(true);
for (i=0; i < alg.length; i++) {
createProgram(i);
execFrame[i].setVisible(true);
alg[i].start();
alg[i].displayAlgorithm();
}
while (true) {
for (i=0; i < alg.length; i++)
if (execPanel[i].isReset()) {
alg[i].terminate();
createProgram(i);
alg[i].start();
execPanel[i].unreset();
}
}
}
} // End class SkaTest
Class 2
package SKA;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Stack;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComboBox;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
#SuppressWarnings("serial")
public
class SkaExecutionPanel extends JDesktopPane {
public static final int EXEC_WIDTH = SkaTest.EXEC_WIDTH-100;
public static final int EXEC_HEIGHT = SkaTest.EXEC_HEIGHT-50;
boolean run = false, pause = true, step = false, reset = false;
JToolBar toolbar = new JToolBar();
JTextArea textOutputArea = new JTextArea();
SkaProgram prog;
Stack<SkaFunction> functionStack = new Stack<SkaFunction>();
SkaFunction currentFunction = null;
int level = 0, in = 30;
public void doCall(String[] subAlg, String subAlgName) {
doCall(subAlg, subAlgName, false); // make non-icon default
}
public void doCall(String[] subAlg, String subAlgName, boolean iconify) {
if (currentFunction != null)
functionStack.push(currentFunction);
currentFunction = new SkaFunction(this, subAlg, subAlgName, iconify);
add(currentFunction, new Integer(1));
currentFunction.setBounds(level*in,level*in,EXEC_WIDTH, EXEC_HEIGHT);
// currentFunction.setBounds(level*in,level*in,EXEC_WIDTH-(level+1)*in, EXEC_HEIGHT-(level+1)*in);
currentFunction.setVisible(true);
level++;
}
public void doReturn() {
if (currentFunction == null)
return;
if (currentFunction.makeIconWhenDone()) {
getDesktopManager().iconifyFrame(currentFunction);
// currentFunction.setIcon(true);
currentFunction.setIconifiable(true);
}
else
currentFunction.setVisible(false);
currentFunction = (SkaFunction) functionStack.pop();
level--;
}
public void displayAlgorithm(String[] a) {
doCall(a, "main");
}
public void displayAlgorithm(String[] a, String aname) {
doCall(a, aname);
}
public void setControlsEnabled(boolean b) {
toolbar.setEnabled(b);
}
class RunAction extends AbstractAction {
RunAction() {
super("run");
}
public void actionPerformed(ActionEvent e) {
run = true; pause = false; step = false;
}
}
class StepAction extends AbstractAction {
StepAction() {
super("step");
}
public void actionPerformed(ActionEvent e) {
run = false; pause = false; step = true;
}
}
class PauseAction extends AbstractAction {
PauseAction() {
super("pause");
}
public void actionPerformed(ActionEvent e) {
pause = true;
// System.out.print("breaks");
// for (int i=0; i<breaks.length; i++)
// System.out.print("[" +i+ "]=" + breaks[i].toString() + " ");
// System.out.println("");
}
}
class ResetAction extends AbstractAction {
ResetAction() {
super("reset");
putValue(Action.SHORT_DESCRIPTION, "stop program and reset state to begining");
}
public void actionPerformed(ActionEvent e) {
run = false; pause = true; step = false;
// should also restart SkaProgram
reset = true;
if (currentFunction != null) currentFunction.reset();
/*
JInternalFrame[] frames = getAllFrames();
for (int i = 0; i < frames.length; i++) {
// frames[i].dispose();
if (frames[i].isIcon())
frames[i].dispose();
}
*/
}
}
JComboBox speedControl;
String speedNames[] = { "slow", "normal", "fast", "very fast" };
int speeds[] = {4000, 2000, 1000, 500} ; // milliseconds
int speed = speeds[1];
private void initSpeedMenu() {
speedControl = new JComboBox(speedNames);
// speedControl.setMaximumRowCount(3);
speedControl.addItemListener(
new ItemListener() {
public void itemStateChanged( ItemEvent e) {
speed = speeds[speedControl.getSelectedIndex()];
}
}
);
speedControl.setSelectedIndex(1);
speedControl.setMaximumSize(speedControl.getPreferredSize());
speedControl.setToolTipText("execution speed");
}
SkaExecutionPanel(JFrame frame) {
initSpeedMenu();
toolbar.add(new RunAction());
toolbar.add(new StepAction());
toolbar.add(new ResetAction());
toolbar.add(new PauseAction());
toolbar.addSeparator();
toolbar.add(speedControl);
// frame.getContentPane().setLayout(new BorderLayout(10,7));
// makeTable();
frame.getContentPane().add("North", toolbar);
Font f = new Font("SansSerif", Font.BOLD, 14);
textOutputArea.setFont(f);
frame.getContentPane().add("South", new JScrollPane(textOutputArea));
// frame.getContentPane().add(this, BorderLayout.CENTER)
// frame.getContentPane().add("Center", toolbar, BorderLayout.NORTH);
// setSize(300,250);
// add toolbar, table, set layout, sizes
}
// public void setAlgorithm(SkaProgram p) {
// prog = p;
// sendAlgorithm(p.getPseudocode());
// }
public int getSpeed() { return speed;
}
public boolean isRunning() { return run;
}
public boolean isPaused() { return pause;
}
public boolean isStepping() { return step;
}
public boolean isReset() { return reset;
}
public void pause() { pause = true;
}
public void unreset() { reset = false;
}
public void aboutToWait() {
currentFunction.aboutToWait();
}
public void doneWait() {
currentFunction.doneWait();
}
public void showToolTipValue(String s) {
currentFunction.showToolTipValue(s);
}
public void showAlgLineBreak(int i) {
currentFunction.showAlgLineBreak(i);
}
public void showAlgLine(int i) {
currentFunction.showAlgLine(i);
}
public void displayText(String s) {
textOutputArea.append(s); // +"\n" add newline?
}
} // End class SkaExecutionPanel
The problem doesn't seem to be in the methods which are being used a lot, it's how frequently you call them which appears to be why they are showing up so frequently. I'd check for all of the calls, see if any are superfluous then go to the third most time consuming method. After that, I would check my algorithms for being particularly intensive. Also, check all method calls and make sure they're not being run without need.
I know this isn't solving the problem itself, but its a start with the information given.
EDIT: The while loop is an infinite loop causing a for loop to run in which every item in an array has been checked to see if its been reset. You can replace this with an observer pattern where when an object is reset, it notifies the observing object which then performs that set of steps. This way you don't have an infinite loop and you cut down on the usage of .isReset(). This is in the main method of Class 1.
Edit 2: Here's the example of an implementation of the observer pattern which is on wikipedia.
"How do I start optimising my Java code?"
You start by profiling it first.
Start with the most intensively used method in your readout and move to less and less intense methods until you find one with a loop construct (for, while). Check the loop construct to see if it is doing too much work, and see if the functions that call this function call it often.
i.e (pseudocode)
dotProduct(vector a, vector b)
{
//create vector dot product here
maths maths maths
}
calc(data)
{
for obj in data:
dotproduct(obj, foo)
}
dotProduct will use the most CPU time, but calc is the place to start - can we cache results? are we recalculating data? Are we iterating through data in a stupid way?
Judging by the function names "isReset()" and "isRunning()" being called a lot, I would guess that you're wasting CPU time polling for a condition/event. Java should have some sort of semaphore/signalling system that you can use to let the do-er notify the wait-er exactly when the event occurs.
First things first. you have a warning in you code somewhere, as that you have used the annotation
#SuppressWarnings("serial"). While this very well may have nothing to with your cpu maxing out. Fix this first and you very well may stumble on the problem.